diff --git a/SAS/ResourceAssignment/ResourceAssigner/lib/resource_assigner.py b/SAS/ResourceAssignment/ResourceAssigner/lib/resource_assigner.py index 565ac5da6838fceb16f2d45c90fa2bca060103cd..a5e1ec4618f96628a822dee440aed7312fdebf31 100755 --- a/SAS/ResourceAssignment/ResourceAssigner/lib/resource_assigner.py +++ b/SAS/ResourceAssignment/ResourceAssigner/lib/resource_assigner.py @@ -206,7 +206,9 @@ class ResourceAssigner(object): # and hence (by the radb triggers) the task has status conflict as well # if task not in conflict, then there was a specification/scheduling error # so put task status to error (not conflict!) - if self.radbrpc.getTask(task['id'])['status'] != 'conflict': + if self.radbrpc.getTask(task['id'])['status'] == 'conflict': + self._finish_resource_assignment(task, 'conflict') + else: self._finish_resource_assignment(task, 'error') def _insert_specification_into_radb(self, otdb_id, specification_tree): @@ -426,7 +428,7 @@ class ResourceAssigner(object): :param specification_tree: specification tree for the main task - :returns 2-tuple (start_time, end_time) + :returns 2-tuple (start_time, end_time) both in datetime format """ def _get_start_and_end_times_from_parset(_parset): @@ -559,6 +561,21 @@ class ResourceAssigner(object): return start_time, end_time + def _get_dwell_parameters(self, specification_tree): + """ + Obtains the min start time, max end time and min/max duration + + :param specification_tree: specification tree for the main task + :return: 4-tuple (minstarttime, maxendtime, minduration, maxduration) + """ + + main_parset = self._get_main_parset(specification_tree) + mom_id = main_parset.getInt('Observation.momID', -1) + time_restrictions = self.momrpc.get_time_restrictions(mom_id) + + return parseDatetime(time_restrictions["minStartTime"]), parseDatetime(time_restrictions["maxEndTime"]), \ + int(time_restrictions["minDuration"]), int(time_restrictions["maxDuration"]) + def _insert_main_task(self, specification_tree, start_time, end_time, cluster_name): """ Inserts the main task and its specification into the RADB. Any existing specification and task with same @@ -649,8 +666,12 @@ class ResourceAssigner(object): :returns: True if successful, or False otherwise """ + start_time, end_time = self._get_main_task_start_and_end_times(specification_tree) + minstarttime, maxendtime, _, _ = self._get_dwell_parameters(specification_tree) + dwell_duration = maxendtime - minstarttime + # For now dwell-behavior is disabled by setting min_starttime/max_starttime to # start_time, because the specification doesn't yet support this. # TODO: enable dwell-scheduling once min_starttime/max_starttime are propagated @@ -658,7 +679,7 @@ class ResourceAssigner(object): resource_availability_checker=self.resource_availability_checker, radbcreds=self.radb_creds, min_starttime=start_time, - max_starttime=start_time, + max_starttime=start_time + dwell_duration, duration=end_time - start_time) try: diff --git a/SAS/ResourceAssignment/ResourceAssigner/lib/schedulers.py b/SAS/ResourceAssignment/ResourceAssigner/lib/schedulers.py index 245efc1a8413a1135d6b92560a89e232b67d0a6e..9e3e6e891a08b7fd7703b518527cc323fa5afd53 100644 --- a/SAS/ResourceAssignment/ResourceAssigner/lib/schedulers.py +++ b/SAS/ResourceAssignment/ResourceAssigner/lib/schedulers.py @@ -42,13 +42,6 @@ class ScheduleException(Exception): super(ScheduleException, self).__init__(message) -class ConflictResolverLastAttemptFailedException(ScheduleException): - """ Exception intended to be raised when a last claim conflict resolving attempt fails """ - - def __init__(self, message): - super(ConflictResolverLastAttemptFailedException, self).__init__(message) - - class BasicScheduler(object): """ A Scheduler that allocates resources at a fixed time. Resources are searched for. """ @@ -432,7 +425,7 @@ class PriorityScheduler(BasicScheduler): # Allow the system X minutes station setup earliest_potential_starttime += timedelta(minutes=self.STATION_SETUP_TIME_MINUTES) - + self._propose_potential_starttime(earliest_potential_starttime) return kill_task_list diff --git a/SAS/ResourceAssignment/ResourceAssigner/test/t_resourceassigner.py b/SAS/ResourceAssignment/ResourceAssigner/test/t_resourceassigner.py index 44f93c2fa7f70d66533484c2411bc23fe4bd7e12..f9227cfdb5dcfd1fab4d6363889fb6d3eef588c3 100755 --- a/SAS/ResourceAssignment/ResourceAssigner/test/t_resourceassigner.py +++ b/SAS/ResourceAssignment/ResourceAssigner/test/t_resourceassigner.py @@ -146,6 +146,11 @@ class ResourceAssignerTest(unittest.TestCase): task_end_time = datetime.datetime(2016, 3, 25, 22, 47, 31) task_start_time = datetime.datetime(2016, 3, 25, 21, 47, 31) + task_minstarttime = task_start_time + task_maxendtime = task_start_time # + datetime.timedelta(hours=1) + task_minduration = 0 + task_maxduration = 0 + non_existing_task_mom_id = -1 predecessor_task_mom_id = 1 @@ -1548,6 +1553,12 @@ class ResourceAssignerTest(unittest.TestCase): self.momrpc_mock = momrpc_patcher.start() self.momrpc_mock.getPredecessorIds.return_value = {str(self.task_mom_id): self.predecessor_task_mom_ids} self.momrpc_mock.getSuccessorIds.return_value = {str(self.task_mom_id): self.successor_task_mom_ids} + self.momrpc_mock.get_time_restrictions.return_value = { + "minStartTime": self.task_minstarttime.strftime('%Y-%m-%d %H:%M:%S'), + "maxEndTime": self.task_maxendtime.strftime('%Y-%m-%d %H:%M:%S'), + "minDuration": str(self.task_minduration), + "maxDuration": str(self.task_maxduration) + } curpc_patcher = mock.patch('lofar.sas.datamanagement.cleanup.rpc') self.addCleanup(curpc_patcher.stop) @@ -2043,6 +2054,7 @@ class ResourceAssignerTest(unittest.TestCase): def test_do_assignment_updates_task_when_it_was_unable_to_claim_some_or_all_resources(self): self.dwell_scheduler_mock().allocate_resources.return_value = False + self.task["status"] = "conflict" self.resource_assigner.do_assignment(self.specification_tree['otdb_id'], self.specification_tree) @@ -2053,6 +2065,7 @@ class ResourceAssignerTest(unittest.TestCase): subject = 'Task' + 'Conflict' self.dwell_scheduler_mock().allocate_resources.return_value = False + self.task["status"] = "conflict" self.resource_assigner.do_assignment(self.specification_tree['otdb_id'], self.specification_tree) @@ -2063,6 +2076,7 @@ class ResourceAssignerTest(unittest.TestCase): subject = 'Task' + 'Conflict' self.dwell_scheduler_mock().allocate_resources.return_value = False + self.task["status"] = "conflict" self.resource_assigner.do_assignment(self.specification_tree['otdb_id'], self.specification_tree) diff --git a/SAS/ResourceAssignment/ResourceAssigner/test/t_schedulers.py b/SAS/ResourceAssignment/ResourceAssigner/test/t_schedulers.py index 579ad82549d24c0b12e4d82cee71781f610fb6ab..f25840546d68e9d517dba0aad8fe474c39518ae2 100755 --- a/SAS/ResourceAssignment/ResourceAssigner/test/t_schedulers.py +++ b/SAS/ResourceAssignment/ResourceAssigner/test/t_schedulers.py @@ -507,8 +507,8 @@ class DwellSchedulerTest(PrioritySchedulerTest): # Second task must have been moved, first task not self.assertEqual(self.fake_ra_database.tasks[0]["starttime"], datetime.datetime(2017, 1, 1, 1, 0, 0)) self.assertEqual(self.fake_ra_database.tasks[0]["endtime"], datetime.datetime(2017, 1, 1, 2, 0, 0)) - self.assertEqual(self.fake_ra_database.tasks[1]["starttime"], datetime.datetime(2017, 1, 1, 2, 0, 0)) - self.assertEqual(self.fake_ra_database.tasks[1]["endtime"], datetime.datetime(2017, 1, 1, 3, 0, 0)) + self.assertEqual(self.fake_ra_database.tasks[1]["starttime"], datetime.datetime(2017, 1, 1, 2, 1, 0)) + self.assertEqual(self.fake_ra_database.tasks[1]["endtime"], datetime.datetime(2017, 1, 1, 3, 1, 0)) def test_dwell_respect_claim_endtime(self): """ Whether a dwelling task will honour the claim endtimes, instead of the task endtime. """ @@ -529,8 +529,8 @@ class DwellSchedulerTest(PrioritySchedulerTest): self.assertTrue(allocation_succesful) # Second task must have been moved beyond claim endtime - self.assertEqual(self.fake_ra_database.tasks[1]["starttime"], datetime.datetime(2017, 1, 1, 3, 0, 0)) - self.assertEqual(self.fake_ra_database.tasks[1]["endtime"], datetime.datetime(2017, 1, 1, 4, 0, 0)) + self.assertEqual(self.fake_ra_database.tasks[1]["starttime"], datetime.datetime(2017, 1, 1, 3, 1, 0)) + self.assertEqual(self.fake_ra_database.tasks[1]["endtime"], datetime.datetime(2017, 1, 1, 4, 1, 0)) if __name__ == '__main__': logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', level=logging.DEBUG)