diff --git a/MAC/APL/MainCU/src/MACScheduler/MACScheduler.cc b/MAC/APL/MainCU/src/MACScheduler/MACScheduler.cc index d9b5a3953f718c732933231ab8d6e37cdbdf45f2..956ec1abab2fba1f16b638da5de8b15d784c731e 100644 --- a/MAC/APL/MainCU/src/MACScheduler/MACScheduler.cc +++ b/MAC/APL/MainCU/src/MACScheduler/MACScheduler.cc @@ -900,11 +900,12 @@ void MACScheduler::_updatePlannedList() for ( ; idx2 >= 0; idx2--) { Json::Value subtask = upcomingSubTasks[idx2]; - // get subtask_id from url. I know, ugly, needs to be in json itself. - vector<string> tmp; + // get subtask_id + string id(subtask["id"].asString()); + int subtask_id = stoi(id); + + // get url string url(subtask["url"].asString()); - boost::split(tmp, url, [](char c){return c == '/';}); - int subtask_id = stoi(tmp[tmp.size()-2]); // construct name and timings info for observation string obsName(observationName(subtask_id)); @@ -1068,11 +1069,12 @@ void MACScheduler::_updateActiveList() // continue; // } - // get subtask_id from url. I know, ugly, needs to be in json itself. - vector<string> tmp; + // get subtask_id + string id(subtask["id"].asString()); + int subtask_id = stoi(id); + + // get url string url(subtask["url"].asString()); - boost::split(tmp, url, [](char c){return c == '/';}); - int subtask_id = stoi(tmp[tmp.size()-2]); // construct name info for observation string obsName(observationName(subtask_id)); @@ -1161,11 +1163,13 @@ void MACScheduler::_updateFinishedList() // continue; // } - // get subtask_id from url. I know, ugly, needs to be in json itself. - vector<string> tmp; + + // get subtask_id + string id(subtask["id"].asString()); + int subtask_id = stoi(id); + + // get url string url(subtask["url"].asString()); - boost::split(tmp, url, [](char c){return c == '/';}); - int subtask_id = stoi(tmp[tmp.size()-2]); // construct name info for observation string obsName(observationName(subtask_id)); diff --git a/SAS/TMSS/src/tmss/tmssapp/migrations/0001_initial.py b/SAS/TMSS/src/tmss/tmssapp/migrations/0001_initial.py index e3ccbb0b1e8fd9aebceb4e3725b984be53f19bec..f19b35a76f07f50442832cea462599935aed7450 100644 --- a/SAS/TMSS/src/tmss/tmssapp/migrations/0001_initial.py +++ b/SAS/TMSS/src/tmss/tmssapp/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 3.0.9 on 2020-10-16 10:16 +# Generated by Django 3.0.9 on 2020-10-27 16:12 from django.conf import settings import django.contrib.postgres.fields @@ -62,7 +62,7 @@ class Migration(migrations.Migration): ('created_at', models.DateTimeField(auto_now_add=True, help_text='Moment of object creation.')), ('updated_at', models.DateTimeField(auto_now=True, help_text='Moment of last object update.')), ('name', models.CharField(help_text='Human-readable name of this object.', max_length=128)), - ('description', models.CharField(blank=True, help_text='A longer description of this object.', max_length=255)), + ('description', models.CharField(blank=True, default='', help_text='A longer description of this object.', max_length=255)), ('rcus', django.contrib.postgres.fields.ArrayField(base_field=models.IntegerField(), size=128)), ('inputs', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=128), blank=True, size=128)), ], @@ -78,7 +78,7 @@ class Migration(migrations.Migration): ('created_at', models.DateTimeField(auto_now_add=True, help_text='Moment of object creation.')), ('updated_at', models.DateTimeField(auto_now=True, help_text='Moment of last object update.')), ('name', models.CharField(help_text='Human-readable name of this object.', max_length=128)), - ('description', models.CharField(blank=True, help_text='A longer description of this object.', max_length=255)), + ('description', models.CharField(blank=True, default='', help_text='A longer description of this object.', max_length=255)), ('location', models.CharField(help_text='Human-readable location of the cluster.', max_length=128)), ('archive_site', models.BooleanField(default=False, help_text='TRUE if this cluster is an archive site, FALSE if not (f.e. a local cluster, or user-owned cluster).')), ], @@ -94,7 +94,7 @@ class Migration(migrations.Migration): ('created_at', models.DateTimeField(auto_now_add=True, help_text='Moment of object creation.')), ('updated_at', models.DateTimeField(auto_now=True, help_text='Moment of last object update.')), ('name', models.CharField(help_text='Human-readable name of this object.', max_length=128)), - ('description', models.CharField(blank=True, help_text='A longer description of this object.', max_length=255)), + ('description', models.CharField(blank=True, default='', help_text='A longer description of this object.', max_length=255)), ('version', models.IntegerField(editable=False, help_text='Version of this template (with respect to other templates of the same name)')), ('schema', django.contrib.postgres.fields.jsonb.JSONField(help_text='Schema for the configurable parameters needed to use this template.')), ], @@ -117,7 +117,7 @@ class Migration(migrations.Migration): ('tags', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=128), blank=True, default=list, help_text='User-defined search keywords for object.', size=8)), ('created_at', models.DateTimeField(auto_now_add=True, help_text='Moment of object creation.')), ('updated_at', models.DateTimeField(auto_now=True, help_text='Moment of last object update.')), - ('description', models.CharField(blank=True, help_text='A longer description of this object.', max_length=255)), + ('description', models.CharField(blank=True, default='', help_text='A longer description of this object.', max_length=255)), ('name', models.CharField(help_text='Human-readable name of this object.', max_length=128, primary_key=True, serialize=False)), ('start', models.DateTimeField(help_text='Moment at which the cycle starts, that is, when its projects can run.')), ('stop', models.DateTimeField(help_text='Moment at which the cycle officially ends.')), @@ -186,7 +186,7 @@ class Migration(migrations.Migration): ('created_at', models.DateTimeField(auto_now_add=True, help_text='Moment of object creation.')), ('updated_at', models.DateTimeField(auto_now=True, help_text='Moment of last object update.')), ('name', models.CharField(help_text='Human-readable name of this object.', max_length=128)), - ('description', models.CharField(blank=True, help_text='A longer description of this object.', max_length=255)), + ('description', models.CharField(blank=True, default='', help_text='A longer description of this object.', max_length=255)), ('version', models.IntegerField(editable=False, help_text='Version of this template (with respect to other templates of the same name)')), ('schema', django.contrib.postgres.fields.jsonb.JSONField(help_text='Schema for the configurable parameters needed to use this template.')), ], @@ -215,7 +215,7 @@ class Migration(migrations.Migration): ('created_at', models.DateTimeField(auto_now_add=True, help_text='Moment of object creation.')), ('updated_at', models.DateTimeField(auto_now=True, help_text='Moment of last object update.')), ('name', models.CharField(help_text='Human-readable name of this object.', max_length=128)), - ('description', models.CharField(blank=True, help_text='A longer description of this object.', max_length=255)), + ('description', models.CharField(blank=True, default='', help_text='A longer description of this object.', max_length=255)), ('version', models.IntegerField(editable=False, help_text='Version of this template (with respect to other templates of the same name)')), ('schema', django.contrib.postgres.fields.jsonb.JSONField(help_text='Schema for the configurable parameters needed to use this template.')), ], @@ -344,7 +344,7 @@ class Migration(migrations.Migration): ('created_at', models.DateTimeField(auto_now_add=True, help_text='Moment of object creation.')), ('updated_at', models.DateTimeField(auto_now=True, help_text='Moment of last object update.')), ('name', models.CharField(help_text='Human-readable name of this object.', max_length=128)), - ('description', models.CharField(blank=True, help_text='A longer description of this object.', max_length=255)), + ('description', models.CharField(blank=True, default='', help_text='A longer description of this object.', max_length=255)), ('capacity', models.BigIntegerField(help_text='Capacity in bytes')), ('directory', models.CharField(help_text='Root directory under which we are allowed to write our data.', max_length=1024)), ], @@ -369,7 +369,7 @@ class Migration(migrations.Migration): ('created_at', models.DateTimeField(auto_now_add=True, help_text='Moment of object creation.')), ('updated_at', models.DateTimeField(auto_now=True, help_text='Moment of last object update.')), ('name', models.CharField(help_text='Human-readable name of this object.', max_length=128)), - ('description', models.CharField(blank=True, help_text='A longer description of this object.', max_length=255)), + ('description', models.CharField(blank=True, default='', help_text='A longer description of this object.', max_length=255)), ('version', models.IntegerField(editable=False, help_text='Version of this template (with respect to other templates of the same name)')), ('schema', django.contrib.postgres.fields.jsonb.JSONField(help_text='Schema for the configurable parameters needed to use this template.')), ('create_function', models.CharField(help_text='Python function to call to execute the generator.', max_length=128)), @@ -393,7 +393,7 @@ class Migration(migrations.Migration): ('tags', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=128), blank=True, default=list, help_text='User-defined search keywords for object.', size=8)), ('created_at', models.DateTimeField(auto_now_add=True, help_text='Moment of object creation.')), ('updated_at', models.DateTimeField(auto_now=True, help_text='Moment of last object update.')), - ('description', models.CharField(blank=True, help_text='A longer description of this object.', max_length=255)), + ('description', models.CharField(blank=True, default='', help_text='A longer description of this object.', max_length=255)), ('name', models.CharField(help_text='Human-readable name of this object.', max_length=128, primary_key=True, serialize=False)), ('priority_rank', models.FloatField(help_text='Priority of this project w.r.t. other projects. Projects can interrupt observations of lower-priority projects.')), ('trigger_priority', models.IntegerField(default=1000, help_text='Priority of this project w.r.t. triggers.')), @@ -438,7 +438,7 @@ class Migration(migrations.Migration): ('tags', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=128), blank=True, default=list, help_text='User-defined search keywords for object.', size=8)), ('created_at', models.DateTimeField(auto_now_add=True, help_text='Moment of object creation.')), ('updated_at', models.DateTimeField(auto_now=True, help_text='Moment of last object update.')), - ('description', models.CharField(blank=True, help_text='A longer description of this object.', max_length=255)), + ('description', models.CharField(blank=True, default='', help_text='A longer description of this object.', max_length=255)), ('name', models.CharField(help_text='Human-readable name of this object.', max_length=128, primary_key=True, serialize=False)), ], options={ @@ -475,7 +475,7 @@ class Migration(migrations.Migration): ('created_at', models.DateTimeField(auto_now_add=True, help_text='Moment of object creation.')), ('updated_at', models.DateTimeField(auto_now=True, help_text='Moment of last object update.')), ('name', models.CharField(help_text='Human-readable name of this object.', max_length=128)), - ('description', models.CharField(blank=True, help_text='A longer description of this object.', max_length=255)), + ('description', models.CharField(blank=True, default='', help_text='A longer description of this object.', max_length=255)), ('version', models.IntegerField(editable=False, help_text='Version of this template (with respect to other templates of the same name)')), ('schema', django.contrib.postgres.fields.jsonb.JSONField(help_text='Schema for the configurable parameters needed to use this template.')), ], @@ -500,7 +500,7 @@ class Migration(migrations.Migration): ('created_at', models.DateTimeField(auto_now_add=True, help_text='Moment of object creation.')), ('updated_at', models.DateTimeField(auto_now=True, help_text='Moment of last object update.')), ('name', models.CharField(help_text='Human-readable name of this object.', max_length=128)), - ('description', models.CharField(blank=True, help_text='A longer description of this object.', max_length=255)), + ('description', models.CharField(blank=True, default='', help_text='A longer description of this object.', max_length=255)), ('version', models.IntegerField(editable=False, help_text='Version of this template (with respect to other templates of the same name)')), ('schema', django.contrib.postgres.fields.jsonb.JSONField(help_text='Schema for the configurable parameters needed to use this template.')), ], @@ -525,7 +525,7 @@ class Migration(migrations.Migration): ('created_at', models.DateTimeField(auto_now_add=True, help_text='Moment of object creation.')), ('updated_at', models.DateTimeField(auto_now=True, help_text='Moment of last object update.')), ('name', models.CharField(help_text='Human-readable name of this object.', max_length=128)), - ('description', models.CharField(blank=True, help_text='A longer description of this object.', max_length=255)), + ('description', models.CharField(blank=True, default='', help_text='A longer description of this object.', max_length=255)), ('generator_doc', django.contrib.postgres.fields.jsonb.JSONField(help_text='Parameters for the generator (NULLable).', null=True)), ], options={ @@ -540,7 +540,7 @@ class Migration(migrations.Migration): ('created_at', models.DateTimeField(auto_now_add=True, help_text='Moment of object creation.')), ('updated_at', models.DateTimeField(auto_now=True, help_text='Moment of last object update.')), ('name', models.CharField(help_text='Human-readable name of this object.', max_length=128)), - ('description', models.CharField(blank=True, help_text='A longer description of this object.', max_length=255)), + ('description', models.CharField(blank=True, default='', help_text='A longer description of this object.', max_length=255)), ('requirements_doc', django.contrib.postgres.fields.jsonb.JSONField(help_text='Scheduling and/or quality requirements for this scheduling unit (IMMUTABLE).')), ('do_cancel', models.BooleanField()), ], @@ -556,7 +556,7 @@ class Migration(migrations.Migration): ('created_at', models.DateTimeField(auto_now_add=True, help_text='Moment of object creation.')), ('updated_at', models.DateTimeField(auto_now=True, help_text='Moment of last object update.')), ('name', models.CharField(help_text='Human-readable name of this object.', max_length=128)), - ('description', models.CharField(blank=True, help_text='A longer description of this object.', max_length=255)), + ('description', models.CharField(blank=True, default='', help_text='A longer description of this object.', max_length=255)), ('requirements_doc', django.contrib.postgres.fields.jsonb.JSONField(help_text='Scheduling and/or quality requirements for this run.')), ('generator_instance_doc', django.contrib.postgres.fields.jsonb.JSONField(help_text='Parameter value that generated this run draft (NULLable).', null=True)), ('scheduling_constraints_doc', django.contrib.postgres.fields.jsonb.JSONField(help_text='Scheduling Constraints for this run.', null=True)), @@ -573,7 +573,7 @@ class Migration(migrations.Migration): ('created_at', models.DateTimeField(auto_now_add=True, help_text='Moment of object creation.')), ('updated_at', models.DateTimeField(auto_now=True, help_text='Moment of last object update.')), ('name', models.CharField(help_text='Human-readable name of this object.', max_length=128)), - ('description', models.CharField(blank=True, help_text='A longer description of this object.', max_length=255)), + ('description', models.CharField(blank=True, default='', help_text='A longer description of this object.', max_length=255)), ('version', models.CharField(help_text='Version of this template (with respect to other templates of the same name).', max_length=128)), ('template', django.contrib.postgres.fields.jsonb.JSONField(help_text='JSON-data compliant with the JSON-schema in the scheduling_unit_template. This observation strategy template like a predefined recipe with all the correct settings, and defines which parameters the user can alter.')), ], @@ -589,7 +589,7 @@ class Migration(migrations.Migration): ('created_at', models.DateTimeField(auto_now_add=True, help_text='Moment of object creation.')), ('updated_at', models.DateTimeField(auto_now=True, help_text='Moment of last object update.')), ('name', models.CharField(help_text='Human-readable name of this object.', max_length=128)), - ('description', models.CharField(blank=True, help_text='A longer description of this object.', max_length=255)), + ('description', models.CharField(blank=True, default='', help_text='A longer description of this object.', max_length=255)), ('version', models.IntegerField(editable=False, help_text='Version of this template (with respect to other templates of the same name)')), ('schema', django.contrib.postgres.fields.jsonb.JSONField(help_text='Schema for the configurable parameters needed to use this template.')), ], @@ -679,7 +679,7 @@ class Migration(migrations.Migration): ('created_at', models.DateTimeField(auto_now_add=True, help_text='Moment of object creation.')), ('updated_at', models.DateTimeField(auto_now=True, help_text='Moment of last object update.')), ('name', models.CharField(help_text='Human-readable name of this object.', max_length=128)), - ('description', models.CharField(blank=True, help_text='A longer description of this object.', max_length=255)), + ('description', models.CharField(blank=True, default='', help_text='A longer description of this object.', max_length=255)), ('version', models.IntegerField(editable=False, help_text='Version of this template (with respect to other templates of the same name)')), ('schema', django.contrib.postgres.fields.jsonb.JSONField(help_text='Schema for the configurable parameters needed to use this template.')), ('queue', models.BooleanField(default=False)), @@ -714,7 +714,7 @@ class Migration(migrations.Migration): ('created_at', models.DateTimeField(auto_now_add=True, help_text='Moment of object creation.')), ('updated_at', models.DateTimeField(auto_now=True, help_text='Moment of last object update.')), ('name', models.CharField(help_text='Human-readable name of this object.', max_length=128)), - ('description', models.CharField(blank=True, help_text='A longer description of this object.', max_length=255)), + ('description', models.CharField(blank=True, default='', help_text='A longer description of this object.', max_length=255)), ('specifications_doc', django.contrib.postgres.fields.jsonb.JSONField(help_text='Schedulings for this task (IMMUTABLE).')), ('do_cancel', models.BooleanField(help_text='Cancel this task.')), ], @@ -742,7 +742,7 @@ class Migration(migrations.Migration): ('created_at', models.DateTimeField(auto_now_add=True, help_text='Moment of object creation.')), ('updated_at', models.DateTimeField(auto_now=True, help_text='Moment of last object update.')), ('name', models.CharField(help_text='Human-readable name of this object.', max_length=128)), - ('description', models.CharField(blank=True, help_text='A longer description of this object.', max_length=255)), + ('description', models.CharField(blank=True, default='', help_text='A longer description of this object.', max_length=255)), ('specifications_doc', django.contrib.postgres.fields.jsonb.JSONField(help_text='Specifications for this task.')), ], options={ @@ -783,7 +783,7 @@ class Migration(migrations.Migration): ('created_at', models.DateTimeField(auto_now_add=True, help_text='Moment of object creation.')), ('updated_at', models.DateTimeField(auto_now=True, help_text='Moment of last object update.')), ('name', models.CharField(help_text='Human-readable name of this object.', max_length=128)), - ('description', models.CharField(blank=True, help_text='A longer description of this object.', max_length=255)), + ('description', models.CharField(blank=True, default='', help_text='A longer description of this object.', max_length=255)), ('version', models.IntegerField(editable=False, help_text='Version of this template (with respect to other templates of the same name)')), ('schema', django.contrib.postgres.fields.jsonb.JSONField(help_text='Schema for the configurable parameters needed to use this template.')), ], @@ -821,7 +821,7 @@ class Migration(migrations.Migration): ('created_at', models.DateTimeField(auto_now_add=True, help_text='Moment of object creation.')), ('updated_at', models.DateTimeField(auto_now=True, help_text='Moment of last object update.')), ('name', models.CharField(help_text='Human-readable name of this object.', max_length=128)), - ('description', models.CharField(blank=True, help_text='A longer description of this object.', max_length=255)), + ('description', models.CharField(blank=True, default='', help_text='A longer description of this object.', max_length=255)), ('version', models.IntegerField(editable=False, help_text='Version of this template (with respect to other templates of the same name)')), ('schema', django.contrib.postgres.fields.jsonb.JSONField(help_text='Schema for the configurable parameters needed to use this template.')), ('validation_code_js', models.CharField(blank=True, default='', help_text='JavaScript code for additional (complex) validation.', max_length=128)), @@ -1177,7 +1177,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='project', name='cycles', - field=models.ManyToManyField(blank=True, help_text='Cycles to which this project belongs (NULLable).', related_name='projects', to='tmssapp.Cycle'), + field=models.ManyToManyField(help_text='Cycles to which this project belongs (NULLable).', null=True, related_name='projects', to='tmssapp.Cycle'), ), migrations.AddField( model_name='project', @@ -1289,7 +1289,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='dataproduct', name='sap', - field=models.ForeignKey(help_text='SAP this dataproduct was generated out of (NULLable).', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='SAP_dataproducts', to='tmssapp.SAP'), + field=models.ForeignKey(help_text='SAP this dataproduct was generated out of (NULLable).', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='dataproducts', to='tmssapp.SAP'), ), migrations.AddField( model_name='dataproduct', diff --git a/SAS/TMSS/src/tmss/tmssapp/models/specification.py b/SAS/TMSS/src/tmss/tmssapp/models/specification.py index 710b9cdd942de6a52ed6c40ebd92d774602b61ae..353f7a16ea0eb7c3f5977161162336f3214e675a 100644 --- a/SAS/TMSS/src/tmss/tmssapp/models/specification.py +++ b/SAS/TMSS/src/tmss/tmssapp/models/specification.py @@ -436,7 +436,8 @@ class CycleQuota(Model): class Project(NamedCommonPK): - cycles = ManyToManyField('Cycle', blank=True, related_name='projects', help_text='Cycles to which this project belongs (NULLable).') + # todo: cycles should be protected since we have to manually decide to clean up projects with a cycle or keep them without cycle, however, ManyToManyField does not allow for that + cycles = ManyToManyField('Cycle', related_name='projects', null=True, help_text='Cycles to which this project belongs (NULLable).') priority_rank = FloatField(null=False, help_text='Priority of this project w.r.t. other projects. Projects can interrupt observations of lower-priority projects.') # todo: add if needed: validators=[MinValueValidator(0.0), MaxValueValidator(1.0)] trigger_priority = IntegerField(default=1000, help_text='Priority of this project w.r.t. triggers.') # todo: verify meaning and add to help_text: "Triggers with higher priority than this threshold can interrupt observations of projects." can_trigger = BooleanField(default=False, help_text='True if this project is allowed to supply observation requests on the fly, possibly interrupting currently running observations (responsive telescope).') @@ -587,6 +588,19 @@ class SchedulingUnitDraft(NamedCommon): class SchedulingUnitBlueprint(NamedCommon): + class Status(Enum): + DEFINED = "defined" + FINISHED = "finished" + CANCELLED = "cancelled" + ERROR = "error" + OBSERVING = "observing" + OBSERVED = "observed" + PROCESSING = "processing" + PROCESSED = "processed" + INGESTING = "ingesting" + SCHEDULED = "scheduled" + SCHEDULABLE = "schedulable" + requirements_doc = JSONField(help_text='Scheduling and/or quality requirements for this scheduling unit (IMMUTABLE).') do_cancel = BooleanField() requirements_template = ForeignKey('SchedulingUnitTemplate', on_delete=CASCADE, help_text='Schema used for requirements_doc (IMMUTABLE).') @@ -657,36 +671,34 @@ class SchedulingUnitBlueprint(NamedCommon): # Determine status per task_type (unfortunately did not manage with updatable view) status_overview_counter = Counter() - status_overview_counter_per_type = {type.value:Counter() for type in TaskType.Choices} - for tb in self.task_blueprints.prefetch_related('specifications_template').all(): + status_overview_counter_per_type = {type.value: Counter() for type in TaskType.Choices} + for tb in self.task_blueprints.select_related('specifications_template').all(): status_overview_counter[tb.status] += 1 status_overview_counter_per_type[tb.specifications_template.type.value][tb.status] += 1 # The actual determination of the SchedulingunitBlueprint status if not self._task_graph_instantiated(): - status = "defined" + return SchedulingUnitBlueprint.Status.DEFINED.value elif self._all_task_finished(status_overview_counter): - status = "finished" + return SchedulingUnitBlueprint.Status.FINISHED.value elif self._any_task_cancelled(status_overview_counter): - status = "cancelled" + return SchedulingUnitBlueprint.Status.CANCELLED.value elif self._any_task_error(status_overview_counter): - status = "error" + return SchedulingUnitBlueprint.Status.ERROR.value elif self._any_task_started_observed_finished(status_overview_counter): if not self._all_observation_task_observed_finished(status_overview_counter_per_type): - status = "observing" + return SchedulingUnitBlueprint.Status.OBSERVING.value elif not self._any_processing_task_started_or_finished(status_overview_counter_per_type): - status = "observed" + return SchedulingUnitBlueprint.Status.OBSERVED.value elif not self._all_processing_tasks_and_observation_tasks_finished(status_overview_counter_per_type): - status = "processing" + return SchedulingUnitBlueprint.Status.PROCESSING.value elif not self._any_ingest_task_started(status_overview_counter_per_type): - status = "processed" + return SchedulingUnitBlueprint.Status.PROCESSED.value else: - status = "ingesting" + return SchedulingUnitBlueprint.Status.INGESTING.value elif self._any_task_scheduled(status_overview_counter): - status = "scheduled" - else: - status = "schedulable" - return status + return SchedulingUnitBlueprint.Status.SCHEDULED.value + return SchedulingUnitBlueprint.Status.SCHEDULABLE.value def _task_graph_instantiated(self): return self._get_total_nbr_tasks() > 0 @@ -734,15 +746,15 @@ class SchedulingUnitBlueprint(NamedCommon): @staticmethod def _get_total_nbr_observation_tasks(status_overview_counter_per_type): - return len(status_overview_counter_per_type[TaskType.Choices.OBSERVATION.value].elements()) + return len(tuple(status_overview_counter_per_type[TaskType.Choices.OBSERVATION.value].elements())) @staticmethod def _get_total_nbr_processing_tasks(status_overview_counter_per_type): - return len(status_overview_counter_per_type[TaskType.Choices.PIPELINE.value].elements()) + return len(tuple(status_overview_counter_per_type[TaskType.Choices.PIPELINE.value].elements())) @staticmethod def _get_total_nbr_ingest_tasks(status_overview_counter_per_type): - return len(status_overview_counter_per_type[TaskType.Choices.INGEST.value].elements()) + return len(tuple(status_overview_counter_per_type[TaskType.Choices.INGEST.value].elements())) class TaskDraft(NamedCommon): @@ -968,27 +980,28 @@ class TaskBlueprint(NamedCommon): if nr_of_subtasks == 0: return "defined" - if len([s for s in subtasks if s['state'] in ('defining','defined')]) == nr_of_subtasks: + if any(s for s in subtasks if s['state'] == 'defining'): return "defined" if len([s for s in subtasks if s['state'] == 'finished']) == nr_of_subtasks: return "finished" - if any(s for s in subtasks if s['state'] == 'scheduled'): - return "scheduled" - if any(s for s in subtasks if s['state'] in ('cancelling', 'cancelled')): return "cancelled" if any(s for s in subtasks if s['state'] == 'error'): return "error" - if any(s for s in subtasks if s['specifications_template__type_id'] == 'observation' and s['state'] in ('cancelling', 'cancelled')): + observations = [s for s in subtasks if s['specifications_template__type_id'] == 'observation'] + if observations and all(obs and obs['state'] in ('finishing', 'finished') for obs in observations): return "observed" if any(s for s in subtasks if s['state'] in ('starting','started','queueing','queued','finishing','finished')): return "started" + if any(s for s in subtasks if s['state'] == 'scheduled'): + return "scheduled" + return "schedulable" diff --git a/SAS/TMSS/test/t_tasks.py b/SAS/TMSS/test/t_tasks.py index 1b4aefc9e56a1dccccb7fdbf92abac85068ace38..6bca6f3f1bc03fac0d59777fb195b5a50230921c 100755 --- a/SAS/TMSS/test/t_tasks.py +++ b/SAS/TMSS/test/t_tasks.py @@ -475,7 +475,7 @@ class SchedulingUnitBlueprintStateTest(unittest.TestCase): subtask.save() # Check task.status as precondition self.assertEqual(task_state, task.status, - "PRECONDITION DOES NOT MET. Expect %s task to be equal to %s (but is %s)" % ( + "INCORRECT PRECONDITION. Expected %s task to have status=%s, but actual status=%s)" % ( task_type, task_state, task.status)) def test_state_with_no_tasks(self): diff --git a/SAS/TMSS/test/tmss_test_data_rest.py b/SAS/TMSS/test/tmss_test_data_rest.py index e0e121edb5c823c74e8619fd8e59c131bebc11de..82f35cf01ae41d98230365c02cc85fbdc0ec8908 100644 --- a/SAS/TMSS/test/tmss_test_data_rest.py +++ b/SAS/TMSS/test/tmss_test_data_rest.py @@ -199,7 +199,7 @@ class TMSSRESTTestDataCreator(): "trigger_priority": 1000, "can_trigger": False, "private_data": True, - "cycles": [], + "cycles": [self.post_data_and_get_url(self.Cycle(), '/cycle')], "archive_subdirectory": 'my_project/'} def ResourceType(self, description="my resource_type description"):