diff --git a/atdb/atdb/settings/dev.py b/atdb/atdb/settings/dev.py index 840632e94242e51880032bdeb394a60ae70f1b1f..d2998259833ca63c52795f8d26fd788df57d5436 100644 --- a/atdb/atdb/settings/dev.py +++ b/atdb/atdb/settings/dev.py @@ -13,7 +13,8 @@ DATABASES = { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'USER': 'atdb_admin', 'PASSWORD': 'atdb123', - 'NAME': 'atdb_ldv_19jan2024', + #'NAME': 'atdb_ldv_19jan2024', + 'NAME': 'atdb_ldv_9feb2024', 'HOST': 'localhost', 'PORT': '5432', }, diff --git a/atdb/run.sh.example b/atdb/run.sh.example deleted file mode 100644 index 0679736b557e35f12110609d48356b5a6e0a4c05..0000000000000000000000000000000000000000 --- a/atdb/run.sh.example +++ /dev/null @@ -1,4 +0,0 @@ -export KEYCLOAK_URL=https://keycloak-sdc.astron.nl -export KEYCLOAK_CLIENT_ID=ATDB-LDV-DEV -export KEYCLOAK_CLIENT_SECRET= -python manage.py runserver --settings=atdb.settings.dev diff --git a/atdb/taskdatabase/migrations/0039_remove_activity_ingestq_status.py b/atdb/taskdatabase/migrations/0039_remove_activity_ingestq_status.py new file mode 100644 index 0000000000000000000000000000000000000000..0badd85b19e746b7233ae809f543bb852963568e --- /dev/null +++ b/atdb/taskdatabase/migrations/0039_remove_activity_ingestq_status.py @@ -0,0 +1,17 @@ +# Generated by Django 5.0 on 2024-02-10 07:03 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('taskdatabase', '0038_remove_activity_priority_remove_activity_workflow_and_more'), + ] + + operations = [ + migrations.RemoveField( + model_name='activity', + name='ingestq_status', + ), + ] diff --git a/atdb/taskdatabase/migrations/0040_activity_ingestq_status.py b/atdb/taskdatabase/migrations/0040_activity_ingestq_status.py new file mode 100644 index 0000000000000000000000000000000000000000..d1b0e9c62553908e1d049358aa47c769538db594 --- /dev/null +++ b/atdb/taskdatabase/migrations/0040_activity_ingestq_status.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0 on 2024-02-10 07:03 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('taskdatabase', '0039_remove_activity_ingestq_status'), + ] + + operations = [ + migrations.AddField( + model_name='activity', + name='ingestq_status', + field=models.JSONField(blank=True, null=True), + ), + ] diff --git a/atdb/taskdatabase/models.py b/atdb/taskdatabase/models.py index 5b40068b10024192a3ba5306e0409aab03c100a7..877ad03b426556e23ec87e36eb223d2ecc7941d7 100644 --- a/atdb/taskdatabase/models.py +++ b/atdb/taskdatabase/models.py @@ -100,7 +100,7 @@ class Activity(models.Model): total_size = models.FloatField(blank=True, null=True) remaining = models.FloatField(blank=True, null=True) - ingestq_status = models.CharField(default="", max_length=100, blank=True, null=True) + ingestq_status = models.JSONField(null=True, blank=True) @property def has_archived(self): diff --git a/atdb/taskdatabase/services/activities.py b/atdb/taskdatabase/services/activities.py index 545084888b61398e55b0669a84a7ca79c594b402..29ea569b4cccbc062c68f9b2b23793ba9d05f0d0 100644 --- a/atdb/taskdatabase/services/activities.py +++ b/atdb/taskdatabase/services/activities.py @@ -93,9 +93,9 @@ def update_activity(task): Depending on the type of status change, certain calculations and updates are performed. Doing this on status change, instead of on-the-fly when a user enters a page, balances the load. - - to 'ARCHIVING, ARCHIVED' : check for incoming 'archive' json from archiver + - to 'ARCHIVING, ARCHIVED, FINISHED' : check for incoming/existing 'archive' json from archiver - to STORED : calculate quality - - to ??? : calculate finished_fraction + - to _FAILED : calculate finished_fraction - to SCRUBBED, ARCHIVING, ARCHIVED, FINISHED : calculate ingested_fraction - always : calc 'verified' @@ -126,7 +126,7 @@ def update_activity(task): # check of any task of this activity already has LTA information. If so, copy to the activity level - if task.status in [State.ARCHIVING.value, State.ARCHIVED.value]: + if task.status in [State.ARCHIVING.value, State.ARCHIVED.value, State.FINISHED.value]: logger.info(f'- add archive json') for t in Task.objects.filter(sas_id=task.sas_id): try: @@ -141,7 +141,7 @@ def update_activity(task): # calculate the finished fraction, this is only used on the Failures page if 'failed' in task.status: - logger.info(f'- calculate_ingested_fraction') + logger.info(f'- calculate_finished_fraction') result = calculate_finished_fraction(task) activity.finished_fraction = result['fraction'] activity.total_size = result['total_size'] diff --git a/atdb/taskdatabase/templates/taskdatabase/index.html b/atdb/taskdatabase/templates/taskdatabase/index.html index f66028be5102df9eb21f2628b393c22ba763b5a6..17e56897798489407000c06e2f55d11cd429fe3e 100644 --- a/atdb/taskdatabase/templates/taskdatabase/index.html +++ b/atdb/taskdatabase/templates/taskdatabase/index.html @@ -31,7 +31,7 @@ {% include 'taskdatabase/pagination.html' %} </div> </div> - <p class="footer"> Version 2 Feb 2024 + <p class="footer"> Version 9 Feb 2024 </div> {% include 'taskdatabase/refresh.html' %} diff --git a/atdb/taskdatabase/tests/test_activities_associate.py b/atdb/taskdatabase/tests/test_activities_associate.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/atdb/taskdatabase/tests/test_filters.py b/atdb/taskdatabase/tests/test_filters.py index 4b1f3b42854075e4e7514c5dd0cee6acab92e419..01bb7a7f372f2a58227acc81f71bfe9261ced775 100644 --- a/atdb/taskdatabase/tests/test_filters.py +++ b/atdb/taskdatabase/tests/test_filters.py @@ -1,17 +1,22 @@ from django.test import TestCase from django.test import RequestFactory from django.contrib.sessions.middleware import SessionMiddleware -from taskdatabase.models import Task +from taskdatabase.models import Task, Workflow, Activity from taskdatabase.views import get_filtered_tasks class FiltersTest(TestCase): def setUp(self): - - self.task1 = Task.objects.create(sas_id=12345,status='defined') - self.task2 = Task.objects.create(sas_id=12345,status='scrubbed') - self.task3 = Task.objects.create(sas_id=12345,status='scrubbed') - self.task4 = Task.objects.create(sas_id=66666,status='scrubbed') - self.task5 = Task.objects.create(sas_id=66666,status='archived_failed') + self.workflow_requantisation = Workflow(id=22, workflow_uri="psrfits_requantisation") + self.workflow_requantisation.save() + self.activity_12345 = Activity.objects.create(sas_id=12345) + self.activity_12345.save() + self.activity_66666 = Activity.objects.create(sas_id=66666) + self.activity_66666.save() + self.task1 = Task.objects.create(sas_id=12345, status='defined', workflow=self.workflow_requantisation, activity = self.activity_12345) + self.task2 = Task.objects.create(sas_id=12345, status='scrubbed', workflow=self.workflow_requantisation, activity = self.activity_12345) + self.task3 = Task.objects.create(sas_id=12345, status='scrubbed', workflow=self.workflow_requantisation, activity = self.activity_12345) + self.task4 = Task.objects.create(sas_id=66666, status='scrubbed', workflow=self.workflow_requantisation, activity = self.activity_66666) + self.task5 = Task.objects.create(sas_id=66666, status='archived_failed', workflow=self.workflow_requantisation, activity = self.activity_66666) def test_without_filter(self): count = 0 diff --git a/atdb/taskdatabase/tests/test_ingest_fraction.py b/atdb/taskdatabase/tests/test_ingest_fraction.py index b50472c8eb86a5b8f03c9729dba2e1d48471e675..98807eea173affaef8f7914d5e619abec4ee8268 100644 --- a/atdb/taskdatabase/tests/test_ingest_fraction.py +++ b/atdb/taskdatabase/tests/test_ingest_fraction.py @@ -1,17 +1,15 @@ from django.test import TestCase - +import json from taskdatabase.models import Task, Workflow class TestIngestFraction(TestCase): def setUp(self): # create a list of Tasks with various values of rfi_percent to test the quality algorithms - workflow_requantisation = Workflow(workflow_uri="psrfits_requantisation") + workflow_requantisation = Workflow(id=22, workflow_uri="psrfits_requantisation") workflow_requantisation.save() Task.objects.get_or_create(filter='a',sas_id=54321, status='stored', workflow=workflow_requantisation) - Task.objects.get_or_create(filter='a',sas_id=54321, status='scrubbed', workflow=workflow_requantisation) - Task.objects.get_or_create(filter='b',sas_id=54321, status='scrubbed', workflow=workflow_requantisation) Task.objects.get_or_create(filter='a',sas_id=54321, status='archiving', workflow=workflow_requantisation) Task.objects.get_or_create(filter='a',sas_id=54321, status='archived', workflow=workflow_requantisation) Task.objects.get_or_create(filter='a',sas_id=54321, status='finishing', workflow=workflow_requantisation) @@ -19,14 +17,18 @@ class TestIngestFraction(TestCase): Task.objects.get_or_create(filter='b',sas_id=54321, status='finished', workflow=workflow_requantisation) Task.objects.get_or_create(filter='a', sas_id=54321, status='discarded', workflow=workflow_requantisation) Task.objects.get_or_create(filter='a', sas_id=54321, status='archived_failed', workflow=workflow_requantisation) + Task.objects.get_or_create(filter='a',sas_id=54321, status='scrubbed', workflow=workflow_requantisation) + Task.objects.get_or_create(filter='b',sas_id=54321, status='scrubbed', workflow=workflow_requantisation) + def test_ingest_fraction(self): # collapse all tasks into a single task for this sas_id task = Task.objects.filter(sas_id=54321).distinct('sas_id')[0] + task.save() # get the list of statusses and level of completion - statusses = task.sasid_ingested_fraction['status'] - completion = task.sasid_ingested_fraction['completion'] + statusses = task.activity.ingestq_status + completion = task.activity.ingested_fraction self.assertEqual(statusses, {'scrubbed': 2, 'archiving': 1, 'archived': 1, 'finishing': 1, 'finished': 2, 'discarded': 1, 'archived_failed': 1}) self.assertEqual(completion,38) diff --git a/atdb/taskdatabase/tests/test_models_joins.py b/atdb/taskdatabase/tests/test_models_joins.py index de89551bb2728545889965b377eabcd3600de9e0..6b50c2702779798aa0348dc495c806297b3a9e43 100644 --- a/atdb/taskdatabase/tests/test_models_joins.py +++ b/atdb/taskdatabase/tests/test_models_joins.py @@ -1,7 +1,7 @@ from django.test import TestCase import json -from taskdatabase.models import Workflow,Task +from taskdatabase.models import Workflow,Task, Activity class TestJoinedTasks(TestCase): @@ -9,15 +9,16 @@ class TestJoinedTasks(TestCase): @classmethod def setUpTestData(cls): - # Set up non-modified objects used by all test methods - workflow = Workflow() - workflow.save() + workflow_requantisation = Workflow(id=22, workflow_uri="psrfits_requantisation") + workflow_requantisation.save() + activity_12345 = Activity.objects.create(sas_id=12345) + activity_12345.save() # create a list of Tasks - Task.objects.get_or_create(sas_id=1, status='stored') - Task.objects.get_or_create(sas_id=2, status='stored') - Task.objects.get_or_create(sas_id=3, status='defined') - Task.objects.get_or_create(sas_id=4, status='defined') + Task.objects.get_or_create(sas_id=1, status='stored', workflow=workflow_requantisation, activity = activity_12345) + Task.objects.get_or_create(sas_id=2, status='stored',workflow=workflow_requantisation, activity = activity_12345) + Task.objects.get_or_create(sas_id=3, status='defined',workflow=workflow_requantisation, activity = activity_12345) + Task.objects.get_or_create(sas_id=4, status='defined',workflow=workflow_requantisation, activity = activity_12345) def test_add_input_tasks_to_task(self): output_task = Task.objects.get(sas_id=1) diff --git a/atdb/taskdatabase/tests/test_path_to_lta.py b/atdb/taskdatabase/tests/test_path_to_lta.py index 38d884bddde566427ac47cd96696c9adfedbe173..3dc2d0e3109b7f21a7e1fe84bf0aa4bbaf5e4b57 100644 --- a/atdb/taskdatabase/tests/test_path_to_lta.py +++ b/atdb/taskdatabase/tests/test_path_to_lta.py @@ -1,35 +1,40 @@ from django.test import TestCase -from taskdatabase.models import Task +from taskdatabase.models import Task, Workflow, Activity class PathToLTATest(TestCase): def setUp(self): - # Create tasks for testing + self.workflow_requantisation = Workflow(id=22, workflow_uri="psrfits_requantisation") + self.workflow_requantisation.save() + self.activity_12345 = Activity.objects.create(sas_id=12345, archive={'path_to_lta': '/sample/path', 'sas_id_archived': 54321}) + self.activity_12345.save() + self.activity_66666 = Activity.objects.create(sas_id=66666, archive={}) + self.activity_66666.save() # the first 2 have no valid path set - self.task1 = Task.objects.create(sas_id=12345,archive={}) - self.task2 = Task.objects.create(sas_id=12345,archive={'path_to_lta': None}) + self.task1 = Task.objects.create(sas_id=12345,archive={}, workflow=self.workflow_requantisation, activity = self.activity_12345) + self.task2 = Task.objects.create(sas_id=12345,archive={'path_to_lta': None}, workflow=self.workflow_requantisation, activity = self.activity_12345) # this task has a valid path_to_lta set - self.task3 = Task.objects.create(sas_id=12345,archive={'path_to_lta': '/sample/path', 'sas_id_archived': 54321}) + self.task3 = Task.objects.create(sas_id=12345,archive={'path_to_lta': '/sample/path', 'sas_id_archived': 54321}, workflow=self.workflow_requantisation, activity = self.activity_12345) # this sasid has no path_to_lta set at all - self.task4 = Task.objects.create(sas_id=66666,archive={}) - self.task5 = Task.objects.create(sas_id=66666,archive={}) + self.task4 = Task.objects.create(sas_id=66666,archive={}, workflow=self.workflow_requantisation, activity = self.activity_66666) + self.task5 = Task.objects.create(sas_id=66666,archive={}, workflow=self.workflow_requantisation, activity = self.activity_66666) def test_path_to_lta_with_path(self): # if only one of the tasks has a path_to_lta, then the other tasks should also return that path for task in Task.objects.filter(sas_id=12345): - result = task.sasid_path_to_lta + result = task.activity.archive['path_to_lta'] self.assertEqual(result, '/sample/path') def test_path_to_lta_without_path(self): # if one of the tasks has 'path_to_lta' set, then return None for task in Task.objects.filter(sas_id=66666): - result = task.sasid_path_to_lta + result = task.path_to_lta self.assertEqual(result, None) - def test_sas_id_has_archived(self): + def test_has_archived(self): # if only one of the tasks has a sas_id_has_archived, then the other tasks should also return that path for task in Task.objects.filter(sas_id=12345): - result = task.sas_id_has_archived + result = task.activity.has_archived self.assertEqual(result, 54321) \ No newline at end of file diff --git a/atdb/taskdatabase/urls.py b/atdb/taskdatabase/urls.py index 11c65788f2e5cb7d98b8c7ab0bd82386db4a9846..0acca01c37cea68132cceeb756aac8bc710880b8 100644 --- a/atdb/taskdatabase/urls.py +++ b/atdb/taskdatabase/urls.py @@ -134,4 +134,6 @@ urlpatterns = [ path('tasks/associate-activities/', views.AssociateActivities, name='associate-activities'), path('tasks/update-all-activities/', views.UpdateAllActivities, name='update-all-activities'), path('tasks/update-failed-tasks/', views.UpdateFailedTasks, name='update-failed-tasks'), + path('tasks/update-ingestq-tasks/', views.UpdateIngestQTasks, name='update-ingestq-tasks'), + path('tasks/update-finished-tasks/', views.UpdateFinishedTasks, name='update-finished-tasks'), ] diff --git a/atdb/taskdatabase/views.py b/atdb/taskdatabase/views.py index 9c5cf32d8e1f01a6772c7ae7d73eb3b1e22ca6c8..d32fae347e0ea0b8483411cb0ad42d632c1d5fe8 100644 --- a/atdb/taskdatabase/views.py +++ b/atdb/taskdatabase/views.py @@ -104,7 +104,7 @@ class ActivityFilter(filters.FilterSet): 'project': ['exact', 'icontains'], 'sas_id': ['exact', 'icontains', 'in'], 'status': ['exact', 'icontains', 'in', 'startswith'], - 'ingestq_status': ['icontains'], + #'ingestq_status': ['icontains'], 'ingested_fraction' : ['exact','lt', 'lte', 'gt', 'gte'], 'finished_fraction': ['exact', 'lt', 'lte', 'gt', 'gte'], 'total_size': ['exact', 'lt', 'lte', 'gt', 'gte'], @@ -1680,12 +1680,13 @@ class GetUniqueValuesForKey(generics.ListAPIView): @staff_member_required def AssociateActivities(request): - tasks = Task.objects.all() + tasks = Task.objects.all().only('sas_id') total = tasks.count() i = 0 for task in tasks: i+=1 - activities.associate_task_with_activity(task) + if task.status not in ['discarded', 'suspended']: + activities.associate_task_with_activity(task) logger.info(f'{i} of {total}') return redirect('index') @@ -1728,4 +1729,33 @@ def UpdateFailedTasks(request): activities.update_activity(task) logger.info(f'{i} of {total}') + return redirect('index') + +@staff_member_required +def UpdateIngestQTasks(request): + tasks = Task.objects.only('sas_id').filter( + Q(status__icontains=State.SCRUBBED.value) | + Q(status__icontains=State.ARCHIVING.value) | + Q(status__icontains=State.ARCHIVED.value) | + Q(status__icontains=State.FINISHING.value)) + + total = tasks.count() + i = 0 + for task in tasks: + i+=1 + activities.update_activity(task) + logger.info(f'{i} of {total}') + + return redirect('index') + +@staff_member_required +def UpdateFinishedTasks(request): + tasks = Task.objects.only('sas_id').filter(status=State.FINISHED.value) + total = tasks.count() + i = 0 + for task in tasks: + i+=1 + activities.update_activity(task) + logger.info(f'{i} of {total}') + return redirect('index') \ No newline at end of file