diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/adapters/reports.py b/SAS/TMSS/backend/src/tmss/tmssapp/adapters/reports.py index 7a4629fdf3bf56d699ce9701c53d9a416a7d56a5..2e292110bd8987bc40ba900fa84f123374374a42 100644 --- a/SAS/TMSS/backend/src/tmss/tmssapp/adapters/reports.py +++ b/SAS/TMSS/backend/src/tmss/tmssapp/adapters/reports.py @@ -21,7 +21,7 @@ def create_cycle_report(request: Request, cycle: models.Cycle, start: datetime, 'observation_hours_per_category': _get_observation_hours_per_category(cycle, start, stop), 'weekly_efficiency': _get_weekly_efficiency(cycle, start, stop), 'data_ingested_per_site_and_category': _get_data_ingested_per_site_and_category(cycle, start, stop), - 'projects_summary': _get_projects_summary(request, cycle), + 'projects_summary': _get_projects_summary(request, cycle, start, stop), 'usage_mode': _get_usage_mode(cycle, start, stop), 'failures': _get_failures(cycle, start, stop), } @@ -207,7 +207,7 @@ def _get_data_ingested_per_site_and_category(cycle: models.Cycle, start: datetim # dataproducts = [ai.dataproduct for ai in archive_info] # Get DataProducts related to the cycle from Subtasks with state 'finished' - dataproducts = models.Dataproduct.objects.filter(producer__subtask__state='finished', producer__subtask__task_blueprints__draft__scheduling_unit_draft__scheduling_set__project__cycles=cycle.pk,producer__subtask__start_time__gte=start, producer__subtask__stop_time__lte=stop) + dataproducts = models.Dataproduct.objects.filter(producer__subtask__state='finished', producer__subtask__task_blueprints__draft__scheduling_unit_draft__scheduling_set__project__cycles=cycle.pk, producer__subtask__start_time__gte=start, producer__subtask__stop_time__lte=stop) # Combine and filter DataProducts accordingly dps_interferometric_obs_sizes = dataproducts.filter(producer__subtask__specifications_template__type='observation', dataformat='MeasurementSet', datatype='visibilities').aggregate(Sum('size')) @@ -225,7 +225,7 @@ def _get_data_ingested_per_site_and_category(cycle: models.Cycle, start: datetim return result -def _get_projects_summary(request: Request, cycle: models.Cycle) -> {}: +def _get_projects_summary(request: Request, cycle: models.Cycle, start: datetime, stop: datetime) -> {}: """ Help function to retrieve projects info. """ @@ -234,7 +234,7 @@ def _get_projects_summary(request: Request, cycle: models.Cycle) -> {}: projects = models.Project.objects.filter(cycles=cycle) for p in projects: # Include the Project report info - projects_summary.append(create_project_report(request, p)) + projects_summary.append(create_project_report(request, p, start, stop)) return projects_summary @@ -312,13 +312,13 @@ def _get_failures(cycle: models.Cycle, start: datetime, stop: datetime) -> {}: # Project Report -def create_project_report(request: Request, project: models.Project) -> {}: +def create_project_report(request: Request, project: models.Project, start: datetime, stop: datetime) -> {}: """ Create a project report as a JSON object. """ - subs, durations = _get_subs_and_durations_from_project(project.pk) + subs, durations = _get_subs_and_durations_from_project(project.pk, start, stop) result = {'project': project.pk, 'quota': _get_quotas_from_project(request, project.pk), 'SUBs': subs, - 'durations': durations, 'LTA dataproducts': _get_lta_dataproducts(project.name), 'SAPs': _get_saps(project.pk)} + 'durations': durations, 'LTA dataproducts': _get_lta_dataproducts(project.name, start, stop), 'SAPs': _get_saps(project.pk)} return result @@ -333,7 +333,7 @@ def _get_quotas_from_project(request: Request, project_pk: int) -> []: return quotas -def _get_subs_and_durations_from_project(project_pk: int) -> ({}, {}): +def _get_subs_and_durations_from_project(project_pk: int, start: datetime, stop: datetime) -> ({}, {}): """ Help function to retrieve durations and scheduling_units distinguished by success/fail. """ @@ -350,6 +350,9 @@ def _get_subs_and_durations_from_project(project_pk: int) -> ({}, {}): durations[f'total_succeeded_{prio.name}'], durations[f'total_observed_succeeded_{prio.name}'] = 0, 0 subs = project_subs.filter(priority_queue=prio.value) for sub in subs: + # Check time interval and go to the next iteration (SUB) if the check fails + if (start and sub.start_time < start) or (stop and sub.stop_time > stop): + continue # Gathering info for reporting sub_start_time = sub.start_time.isoformat() if sub.start_time else None sub_stop_time = sub.stop_time.isoformat() if sub.stop_time else None @@ -397,15 +400,19 @@ def _get_subs_and_durations_from_project(project_pk: int) -> ({}, {}): return subs, durations -def _get_lta_dataproducts(project_name: str) -> {}: +def _get_lta_dataproducts(project_name: str, start: datetime, stop: datetime) -> {}: """ Help function to retrieve the sum of the LTA dataproducts sizes. """ # Query dataproducts from Subtasks of type 'ingest' within 'finished' status - return models.Dataproduct.objects.filter(producer__subtask__specifications_template__type='ingest') \ + dataproducts = models.Dataproduct.objects.filter(producer__subtask__specifications_template__type='ingest') \ .filter(producer__subtask__state__value='finished') \ - .filter(producer__subtask__task_blueprints__draft__scheduling_unit_draft__scheduling_set__project__name=project_name) \ - .aggregate(Sum('size')) + .filter(producer__subtask__task_blueprints__draft__scheduling_unit_draft__scheduling_set__project__name=project_name) + # Filter basing on date interval if passed + dataproducts = dataproducts.filter(producer__subtask__start_time__gte=start) if start else dataproducts + dataproducts = dataproducts.filter(producer__subtask__stop_time__lte=stop) if stop else dataproducts + + return dataproducts.aggregate(Sum('size')) def _get_saps(project_pk: int) -> []: diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/specification.py b/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/specification.py index b38df00c13a467b2589736eaa312710e68141a2c..38975d7b2a62e9b791b993fea8c1ba391e2a38a2 100644 --- a/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/specification.py +++ b/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/specification.py @@ -413,27 +413,21 @@ class ProjectViewSet(LOFARViewSet): def report(self, request, pk=None): project = get_object_or_404(models.Project, pk=pk) - # TODO: Project model doesn't have a start and stop properties. - # # Check start and stop times - # start, stop = request.query_params.get('start', None), request.query_params.get('stop', None) - # if start: - # try: - # start = dateutil.parser.parse(start, ignoretz=True) - # except Exception: - # return Response('Error: please specify an isoformat timestamp for start_time', status=400) - # if stop: - # try: - # stop = dateutil.parser.parse(stop, ignoretz=True) - # except Exception: - # return Response('Error: please specify an isoformat timestamp for stop_time', status=400) - # - # if not start or start < project.start: - # start = project.start - # if not stop or stop > project.stop: - # stop = project.stop + # Check start and stop times + start, stop = request.query_params.get('start', None), request.query_params.get('stop', None) + if start: + try: + start = dateutil.parser.parse(start, ignoretz=True) + except Exception: + return Response('Error: please specify an isoformat timestamp for start_time', status=400) + if stop: + try: + stop = dateutil.parser.parse(stop, ignoretz=True) + except Exception: + return Response('Error: please specify an isoformat timestamp for stop_time', status=400) try: - result = create_project_report(request, project) + result = create_project_report(request, project, start, stop) except RuntimeError: return Response('Error: workflowapp is not running. It is needed to retrieve some reporting information.', status=status.HTTP_503_SERVICE_UNAVAILABLE) return Response(result, status=status.HTTP_200_OK)