diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/views.py b/SAS/TMSS/backend/src/tmss/tmssapp/views.py index f999b495fb48ffccda5d3c89250bdfc63ae07846..86cd66f5b3a8736999419214daeb70b670e7d656 100644 --- a/SAS/TMSS/backend/src/tmss/tmssapp/views.py +++ b/SAS/TMSS/backend/src/tmss/tmssapp/views.py @@ -1,12 +1,19 @@ import os +import logging +logger = logging.getLogger(__name__) + from django.http import HttpResponse, JsonResponse, Http404 +from rest_framework.response import Response as RestResponse +from rest_framework import status from django.shortcuts import get_object_or_404, render, redirect from lofar.sas.tmss.tmss.tmssapp import models from lofar.common.json_utils import get_default_json_object_for_schema from lofar.common.datetimeutils import formatDatetime +from lofar.common.util import single_line_with_single_spaces from lofar.sas.tmss.tmss.tmssapp.adapters.parset import convert_to_parset from lofar.sas.tmss.tmss.tmssapp.adapters.reports import create_cycle_report +from lofar.sas.tmss.tmss.tmssapp.tasks import create_scheduling_unit_draft_from_observing_strategy_template, create_task_blueprints_and_subtasks_from_scheduling_unit_draft from drf_yasg.utils import swagger_auto_schema from drf_yasg.openapi import Parameter from rest_framework.authtoken.models import Token @@ -14,6 +21,7 @@ from rest_framework.permissions import AllowAny from rest_framework.decorators import authentication_classes, permission_classes from django.apps import apps import re +from lofar.sas.tmss.tmss.tmssapp.serializers import SchedulingUnitDraftSerializer, SchedulingUnitBlueprintSerializer from rest_framework.decorators import api_view from datetime import datetime @@ -343,3 +351,43 @@ def get_cycles_report(request): results[c_pk] = create_cycle_report(request, c) return JsonResponse(results) + + +@api_view(['POST']) +def submit_trigger(request): + trigger_doc = request.data + logger.info("Received trigger submission: %s", single_line_with_single_spaces(trigger_doc)) + + # check if doc is valid + trigger_template = get_object_or_404(models.CommonSchemaTemplate, name="triggers") + trigger_template.validate_document(trigger_doc) + + # gather relevant objects from db + strategy_template = get_object_or_404(models.SchedulingUnitObservingStrategyTemplate, name=trigger_doc['scheduling_unit_observing_strategy_template']['name'], version=trigger_doc['scheduling_unit_observing_strategy_template']['version']) + scheduling_set = get_object_or_404(models.SchedulingSet, pk=trigger_doc['scheduling_set_id']) + + # check permissions + if not scheduling_set.project.can_trigger: + msg = 'Project \'%s\' does not allow triggers' % scheduling_set.project + logger.error(msg) + return RestResponse(msg, status=status.HTTP_403_FORBIDDEN) + + # try to create the draft from the trigger_doc + scheduling_unit_draft = create_scheduling_unit_draft_from_observing_strategy_template(strategy_template, + scheduling_set, + name=trigger_doc['name'], + description=trigger_doc.get('description'), + requirements_doc_overrides=trigger_doc['scheduling_unit_observing_strategy_template'].get('overrides', {})) + + # indicate that we are allowed to interrupt the telescope + scheduling_unit_draft.interrupts_telescope = True + scheduling_unit_draft.save() + + # if the trigger mode is 'run', then turn it into a blueprint which the dynamic scheduler will try to pick up, given the scheduling constraints + if trigger_doc['mode'].lower() == 'run': + scheduling_unit_blueprint = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft) + return RestResponse(SchedulingUnitBlueprintSerializer(scheduling_unit_blueprint, context={'request': request}).data, + status=status.HTTP_201_CREATED) + + return RestResponse(SchedulingUnitDraftSerializer(scheduling_unit_draft, context={'request': request}).data, + status=status.HTTP_201_CREATED) diff --git a/SAS/TMSS/backend/src/tmss/urls.py b/SAS/TMSS/backend/src/tmss/urls.py index 9fa829be21aba757509a78d34eebe9f8c4848ba8..a10d10f5de759045d18f3e9c1d7d3451484a835a 100644 --- a/SAS/TMSS/backend/src/tmss/urls.py +++ b/SAS/TMSS/backend/src/tmss/urls.py @@ -79,6 +79,7 @@ urlpatterns = [ re_path('util/target_rise_and_set/?', views.get_target_rise_and_set, name='get_target_rise_and_set'), re_path('util/target_transit/?', views.get_target_transit, name='get_target_transit'), re_path('util/cycles_report/?', views.get_cycles_report, name='get_cycles_report'), + re_path('submit_trigger', views.submit_trigger, name='submit_trigger'), ] if os.environ.get('SHOW_DJANGO_DEBUG_TOOLBAR', False): diff --git a/SAS/TMSS/client/bin/tmss_trigger_simple_observation b/SAS/TMSS/client/bin/tmss_submit_trigger similarity index 89% rename from SAS/TMSS/client/bin/tmss_trigger_simple_observation rename to SAS/TMSS/client/bin/tmss_submit_trigger index 497409792a2ca0749e47a6c5f8a879f3ca5c406d..776b6789a17d732573f0c20a6759e94308bce5ca 100755 --- a/SAS/TMSS/client/bin/tmss_trigger_simple_observation +++ b/SAS/TMSS/client/bin/tmss_submit_trigger @@ -17,7 +17,7 @@ # You should have received a copy of the GNU General Public License along # with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. -from lofar.sas.tmss.client.mains import main_trigger_scheduling_unit +from lofar.sas.tmss.client.mains import main_submit_trigger if __name__ == "__main__": - main_trigger_scheduling_unit() + main_submit_trigger() diff --git a/SAS/TMSS/client/lib/mains.py b/SAS/TMSS/client/lib/mains.py index e933248fc6c79b683ad6c5296997df71d6c299d0..d1601e4ecf644e5a370c86e607415d5dde868e57 100644 --- a/SAS/TMSS/client/lib/mains.py +++ b/SAS/TMSS/client/lib/mains.py @@ -3,6 +3,7 @@ import argparse from pprint import pprint from lofar.sas.tmss.client.tmss_http_rest_client import TMSSsession from lofar.common.datetimeutils import parseDatetime +from lofar.common.util import dict_search_and_replace import dateutil.parser import datetime @@ -194,7 +195,7 @@ def main_set_setting(): exit(1) -def main_trigger_scheduling_unit(): +def main_submit_trigger(): ''' ''' parser = argparse.ArgumentParser() @@ -207,59 +208,38 @@ def main_trigger_scheduling_unit(): parser.add_argument("--target_name", type=str, default='target1', help="The name of the observation target. Defaults to 'target1'.") parser.add_argument("duration", type=int, help="The duration of the observation in seconds.") parser.add_argument("scheduling_set_id", type=int, help="The ID of the scheduling set the trigger should be placed in. This should've been provided to you.") - parser.add_argument("test", type=bool, default=True, help="Whether this is a test submission or should be actually performed. Set False to submit a real trigger. Defaults to True.") + parser.add_argument("--mode", type=str, required=True, help="Which trigger mode? 'test' or 'run'. Specify Whether this is a test submission or should be actually run.") parser.add_argument('-R', '--rest_api_credentials', type=str, default='TMSSClient', help='TMSS django REST API credentials name, default: TMSSClient') args = parser.parse_args() try: import uuid - from lofar.common.util import dict_search_and_replace with TMSSsession.create_from_dbcreds_for_ldap(dbcreds_name=args.rest_api_credentials) as session: - strategy_template = session.get_scheduling_unit_observing_strategy_template(args.observing_strategy_template) - requirements = strategy_template['template'] - - dict_search_and_replace(requirements['tasks'], 'angle1', args.pointing_angle1) - dict_search_and_replace(requirements['tasks'], 'angle2', args.pointing_angle2) - dict_search_and_replace(requirements['tasks'], 'name', args.target_name) - dict_search_and_replace(requirements['tasks'], 'target', args.target_name) - dict_search_and_replace(requirements['tasks'], 'duration', args.duration) - - constraints = {"sky": { - "min_distance": { - "sun": 0.0, - "moon": 0.0, - "jupiter": 0.0 - }, - "transit_offset": { - "to": 7200, - "from": -7200 - }, - "min_target_elevation": 0.0 - }} + # get a prepared valid trigger_doc for the requested template + trigger_doc = session.get_trigger_specification_doc_for_scheduling_unit_observing_strategy_template(args.observing_strategy_template) + + # alter it with our parameters + trigger_doc["name"] = "CLI_trigger_%s" % (uuid.uuid4()) + trigger_doc["description"] = "Trigger submitted via CLI tools: %s" % args.observing_strategy_template + trigger_doc["mode"] = args.mode + trigger_doc["scheduling_set_id"] = args.scheduling_set_id + overrides = trigger_doc['scheduling_unit_observing_strategy_template']['overrides'] + + # this is a bit flacky, as it assumes that these parameters are available in the overrides dict + dict_search_and_replace(overrides, 'angle1', args.pointing_angle1) + dict_search_and_replace(overrides, 'angle2', args.pointing_angle2) + dict_search_and_replace(overrides, 'name', args.target_name) + dict_search_and_replace(overrides, 'target', args.target_name) + dict_search_and_replace(overrides, 'duration', args.duration) if args.end_before: - constraints.setdefault('time', {})['before'] = args.end_before + overrides['scheduling_constraints_doc']['time']['before'] = args.end_before if args.start_at: - constraints.setdefault('time', {})['at'] = args.start_at - - scheduling_unit_data = {"name": "CLI_trigger_%s" % (uuid.uuid4()), - "description": "Trigger submitted via CLI tools: %s" % strategy_template['name'], - "tags": [], - "requirements_doc": requirements, - "copy_reason": None, - "generator_instance_doc": None, - "copies": None, - "scheduling_set": session.api_url + '/scheduling_set/%s/' % args.scheduling_set_id, - "requirements_template": session.api_url + '/scheduling_unit_template/1/', - "observation_strategy_template": strategy_template['url'], - "scheduling_constraints_template_id": 1, - "scheduling_constraints_doc": constraints, - "interrupts_telescope": True, - "scheduling_unit_blueprints": [], - "task_drafts": []} - pprint(session.trigger_scheduling_unit(json_data=scheduling_unit_data, test=args.test)) + overrides['overrides']['scheduling_constraints_doc']['time']['at'] = args.start_at + + pprint(session.submit_trigger(trigger_doc)) except Exception as e: print(e) - exit(1) \ No newline at end of file + exit(1)