From f76c9c8091822b10ceb1c81f07ff1c8491f4b1f3 Mon Sep 17 00:00:00 2001 From: Jorrit Schaap <schaap@astron.nl> Date: Thu, 4 Jun 2020 13:59:34 +0200 Subject: [PATCH] TMSS-207: call generic create_subtasks_from_task_blueprint from REST action, lookup generator method(s), and create the actual subtasks. --- SAS/TMSS/src/tmss/exceptions.py | 3 + SAS/TMSS/src/tmss/tmssapp/subtasks.py | 55 +++++++++++-------- .../tmss/tmssapp/viewsets/specification.py | 5 +- 3 files changed, 39 insertions(+), 24 deletions(-) diff --git a/SAS/TMSS/src/tmss/exceptions.py b/SAS/TMSS/src/tmss/exceptions.py index c77b7226f04..ccdf97362bd 100644 --- a/SAS/TMSS/src/tmss/exceptions.py +++ b/SAS/TMSS/src/tmss/exceptions.py @@ -8,6 +8,9 @@ class SchemaValidationException(TMSSException): class ConversionException(TMSSException): pass +class SubtaskCreationException(ConversionException): + pass + class SchedulingException(TMSSException): pass diff --git a/SAS/TMSS/src/tmss/tmssapp/subtasks.py b/SAS/TMSS/src/tmss/tmssapp/subtasks.py index 418d4bf1e03..abb418e029d 100644 --- a/SAS/TMSS/src/tmss/tmssapp/subtasks.py +++ b/SAS/TMSS/src/tmss/tmssapp/subtasks.py @@ -3,7 +3,7 @@ logger = logging.getLogger(__name__) from lofar.common.json_utils import add_defaults_to_json_object_for_schema, get_default_json_object_for_schema -from lofar.sas.tmss.tmss.exceptions import SubtaskSchedulingException, ConversionException +from lofar.sas.tmss.tmss.exceptions import SubtaskCreationException, SubtaskSchedulingException from datetime import datetime, timedelta from lofar.common.datetimeutils import parseDatetime @@ -12,6 +12,31 @@ from lofar.sas.tmss.tmss.tmssapp.models import * # ==== various create* methods to convert/create a TaskBlueprint into one or more Subtasks ==== +def check_prerequities_for_subtask_creation(task_blueprint: TaskBlueprint) -> bool: + if task_blueprint.do_cancel: + raise SubtaskCreationException("Cannot create subtasks from task_blueprint id=%d, because the task_blueprint is explicit set to cancel." % task_blueprint.id) + + return True + +def create_subtasks_from_task_blueprint(task_blueprint: TaskBlueprint) -> [Subtask]: + '''Generic create-method for subtasks. Calls the appropiate create method based on the task_blueprint specifications_template name.''' + check_prerequities_for_subtask_creation(task_blueprint) + + # fixed mapping from template name to generator functions which create the list of subtask(s) for this task_blueprint + generators_mapping = {'correlator schema': [create_observation_control_subtask_from_task_blueprint, + create_qafile_subtask_from_task_blueprint, + create_qaplots_subtask_from_task_blueprint], + 'preprocessing schema': [create_preprocessing_subtask_from_task_blueprint]} + + template_name = task_blueprint.specifications_template.name + if template_name in generators_mapping: + generators = generators_mapping[template_name] + subtasks = [generator(task_blueprint) for generator in generators] + return subtasks + else: + raise SubtaskCreationException('Cannot create subtasks for task id=%s because no generator exists for its schema name=%s' % (task_blueprint.pk, template_name)) + + def create_observation_control_subtask_from_task_blueprint(task_blueprint: TaskBlueprint) -> Subtask: """ Create an observation control subtask . @@ -19,9 +44,7 @@ def create_observation_control_subtask_from_task_blueprint(task_blueprint: TaskB https://support.astron.nl/confluence/display/TMSS/Specification+Flow """ # step 0: check pre-requisites - if task_blueprint.do_cancel: - raise ValueError("Cancel create subtasks from blueprint task id=%d, because its explicit set to cancel" % - task_blueprint.id) + check_prerequities_for_subtask_creation(task_blueprint) # step 1: create subtask in defining state subtask_template = SubtaskTemplate.objects.get(name='observationcontrol schema') @@ -43,7 +66,7 @@ def create_observation_control_subtask_from_task_blueprint(task_blueprint: TaskB } } specifications_doc = add_defaults_to_json_object_for_schema(extra_specifications_doc, subtask_template.schema) - cancel = datetime.datetime.utcnow().isoformat() # I dont understand why this should be a dateformat and not a boolean ? + cancel = datetime.utcnow().isoformat() # I dont understand why this should be a dateformat and not a boolean ? cluster_name = task_blueprint.specifications_doc.get("storage_cluster", "CEP4") subtask_data = { "start_time": None, "stop_time": None, @@ -72,10 +95,10 @@ def create_observation_control_subtask_from_task_blueprint(task_blueprint: TaskB def create_qafile_subtask_from_task_blueprint(task_blueprint: TaskBlueprint) -> Subtask: observation_subtasks = [st for st in task_blueprint.subtasks.all() if st.specifications_template.type.value == SubtaskType.Choices.OBSERVATION.value] if not observation_subtasks: - raise ValueError("Cannot create %s subtask for task_blueprint id=%d because it has no observation subtask(s)" % ( + raise SubtaskCreationException("Cannot create %s subtask for task_blueprint id=%d because it has no observation subtask(s)" % ( SubtaskType.Choices.QA_FILES.value, task_blueprint.pk)) - observation_subtask = observation_subtasks.first() # TODO: decide what to do when there are multiple observation subtasks? + observation_subtask = observation_subtasks[0] # TODO: decide what to do when there are multiple observation subtasks? return create_qafile_subtask_from_observation_subtask(observation_subtask) @@ -139,7 +162,7 @@ def create_qaplots_subtask_from_task_blueprint(task_blueprint: TaskBlueprint) -> raise ValueError("Cannot create %s subtask for task_blueprint id=%d because it has no qafile subtask(s)" % ( SubtaskType.Choices.QA_FILES.value, task_blueprint.pk)) - qafile_subtask = qafile_subtasks.first() # TODO: decide what to do when there are multiple qafile subtasks? + qafile_subtask = qafile_subtasks[0] # TODO: decide what to do when there are multiple qafile subtasks? return create_qaplots_subtask_from_qafile_subtask(qafile_subtask) @@ -368,34 +391,20 @@ def connect_observation_subtask_to_preprocessing_subtask(observation_subtask: Su pipeline_subtask_output.dataproducts.set(output_dps) -def create_subtasks_from_task_blueprint(task_blueprint: TaskBlueprint): - generator_mapping = {'preprocessing schema': create_preprocessing_subtask_from_task_blueprint } - template_name = task_blueprint.specifications_template.name - if template_name in generator_mapping: - generator = generator_mapping[template_name] - return generator(task_blueprint) - else: - raise ValueError('Cannot create subtasks for task id=%s since no generator exists for its schema name=%s' % (task_blueprint.pk, template_name)) - - def create_preprocessing_subtask_from_task_blueprint(task_blueprint: TaskBlueprint) -> Subtask: # todo: check whether already created to avoid duplication? subtask_template = SubtaskTemplate.objects.get(name='pipelinecontrol schema') default_subtask_specs = get_default_json_object_for_schema(subtask_template.schema) - subtasks = [] subtask_specs = _generate_subtask_specs_from_preprocessing_task_specs(task_blueprint.specifications_doc, default_subtask_specs) subtask = create_subtask(subtask_template, subtask_specs) subtask.task_blueprint = task_blueprint subtask.cluster = Cluster.objects.get(name="CEP4") # todo: probably should not be hardcoded? Can be optional in parset? subtask.save() - subtasks.append(subtask) - SubtaskTemplate.objects.get(name='pipelinecontrol schema') - - return {'subtasks_created': [s.pk for s in subtasks]} # todo: determine observation subtask, then call connect_observation_subtask_to_preprocessing_subtask to create inputs (not sure where exactly this should happen) + return subtask def _generate_subtask_specs_from_preprocessing_task_specs(preprocessing_task_specs, default_subtask_specs): diff --git a/SAS/TMSS/src/tmss/tmssapp/viewsets/specification.py b/SAS/TMSS/src/tmss/tmssapp/viewsets/specification.py index 9edd4e04e40..98781f242cb 100644 --- a/SAS/TMSS/src/tmss/tmssapp/viewsets/specification.py +++ b/SAS/TMSS/src/tmss/tmssapp/viewsets/specification.py @@ -259,7 +259,10 @@ class TaskBlueprintViewSet(LOFARViewSet): def create_subtasks(self, request, pk=None): task_blueprint = get_object_or_404(models.TaskBlueprint, pk=pk) subtasks = create_subtasks_from_task_blueprint(task_blueprint) - return JsonResponse(subtasks) + + # return a response with the new serialized Subtasks + serialized_subtasks = serializers.SubtaskSerializer(subtasks, many=True, context={'request':request}).data + return Response(serialized_subtasks, status=status.HTTP_201_CREATED) class TaskBlueprintNestedViewSet(LOFARNestedViewSet): -- GitLab