From 76a3f0b88cf6cbcc26f329842cdb64d55c16a738 Mon Sep 17 00:00:00 2001 From: jlope2 Date: Fri, 18 Nov 2016 14:12:42 +0100 Subject: [PATCH 01/25] Added script to run unit suite & .gitignore updated --- .gitignore | 2 ++ test/run_unit_suite.py | 2 ++ 2 files changed, 4 insertions(+) create mode 100644 test/run_unit_suite.py diff --git a/.gitignore b/.gitignore index bd137496e..c748715fb 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ .*.sw* .*.pyc* .*.log* +/cover/ +/.coverage diff --git a/test/run_unit_suite.py b/test/run_unit_suite.py new file mode 100644 index 000000000..019e593d1 --- /dev/null +++ b/test/run_unit_suite.py @@ -0,0 +1,2 @@ +import os +os.system("nosetests --with-coverage --cover-erase --cover-package=autosubmit --cover-html test/unit") -- GitLab From 5696c36a777a6bb740d1a08189f5abc861edb6da Mon Sep 17 00:00:00 2001 From: jlope2 Date: Fri, 18 Nov 2016 15:32:36 +0100 Subject: [PATCH 02/25] Fixed typo --- test/unit/{test_basic_ config.py => test_basic_config.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/unit/{test_basic_ config.py => test_basic_config.py} (100%) diff --git a/test/unit/test_basic_ config.py b/test/unit/test_basic_config.py similarity index 100% rename from test/unit/test_basic_ config.py rename to test/unit/test_basic_config.py -- GitLab From 6d52533cdeae3dcf992f99e543b7b987747b85cc Mon Sep 17 00:00:00 2001 From: jlope2 Date: Fri, 18 Nov 2016 17:02:10 +0100 Subject: [PATCH 03/25] Some pythonic refactors --- autosubmit/job/job.py | 35 ++++++++++++++++------------- autosubmit/job/job_list.py | 18 +++++++-------- autosubmit/platforms/lsfplatform.py | 2 +- autosubmit/platforms/platform.py | 3 ++- test/unit/test_dic_jobs.py | 2 +- test/unit/test_job.py | 23 ++++++++++--------- 6 files changed, 44 insertions(+), 39 deletions(-) diff --git a/autosubmit/job/job.py b/autosubmit/job/job.py index 3d3e479a4..b98eb97a2 100644 --- a/autosubmit/job/job.py +++ b/autosubmit/job/job.py @@ -30,7 +30,7 @@ from autosubmit.config.basicConfig import BasicConfig from autosubmit.date.chunk_date_lib import * -class Job: +class Job(object): """ Class to handle all the tasks with Jobs at HPC. A job is created by default with a name, a jobid, a status and a type. @@ -107,20 +107,20 @@ class Job: Log.debug('FAIL_COUNT: {0}', self.fail_count) Log.debug('EXPID: {0}', self.expid) - # Properties @property def parents(self): """ - Return parent jobs list + Returns parent jobs list :return: parent jobs :rtype: set """ return self._parents - def get_platform(self): + @property + def platform(self): """ - Returns the platforms to be used by the job. Chooses between serial and parallel platforms + Returns the platform to be used by the job. Chooses between serial and parallel platforms :return HPCPlatform object for the job to use :rtype: HPCPlatform @@ -130,7 +130,8 @@ class Job: else: return self._platform.serial_platform - def set_platform(self, value): + @platform.setter + def platform(self, value): """ Sets the HPC platforms to be used by the job. @@ -139,7 +140,8 @@ class Job: """ self._platform = value - def get_queue(self): + @property + def queue(self): """ Returns the queue to be used by the job. Chooses between serial and parallel platforms @@ -153,7 +155,8 @@ class Job: else: return self._platform.serial_platform.serial_queue - def set_queue(self, value): + @queue.setter + def queue(self, value): """ Sets the queue to be used by the job. @@ -401,7 +404,7 @@ class Job: if new_status == Status.COMPLETED: Log.debug("This job seems to have completed...checking") - self.get_platform().get_completed_files(self.name) + self.platform.get_completed_files(self.name) self.check_completion() else: self.status = new_status @@ -415,7 +418,7 @@ class Job: Log.user_warning("Job {0} is FAILED", self.name) elif self.status is Status.UNKNOWN: Log.debug("Job {0} in UNKNOWN status. Checking completed files", self.name) - self.get_platform().get_completed_files(self.name) + self.platform.get_completed_files(self.name) self.check_completion(Status.UNKNOWN) if self.status is Status.UNKNOWN: Log.warning('Job {0} in UNKNOWN status', self.name) @@ -431,7 +434,7 @@ class Job: if self.status in [Status.COMPLETED, Status.FAILED, Status.UNKNOWN]: self.write_end_time(self.status == Status.COMPLETED) if copy_remote_logs: - self.get_platform().get_logs_files(self.expid, self.out_filename, self.err_filename) + self.platform.get_logs_files(self.expid, self.out_filename, self.err_filename) return self.status def check_completion(self, default_status=Status.FAILED): @@ -516,7 +519,7 @@ class Job: else: parameters['Chunk_LAST'] = 'FALSE' - job_platform = self.get_platform() + job_platform = self.platform self.processors = as_conf.get_processors(self.section) self.threads = as_conf.get_threads(self.section) self.tasks = as_conf.get_tasks(self.section) @@ -539,7 +542,7 @@ class Job: parameters['CURRENT_ARCH'] = job_platform.name parameters['CURRENT_HOST'] = job_platform.host - parameters['CURRENT_QUEUE'] = self.get_queue() + parameters['CURRENT_QUEUE'] = self.queue parameters['CURRENT_USER'] = job_platform.user parameters['CURRENT_PROJ'] = job_platform.project parameters['CURRENT_BUDG'] = job_platform.budget @@ -610,7 +613,7 @@ class Job: snippet.as_tailer()]) def _get_paramiko_template(self, snippet, template): - current_platform = self.get_platform() + current_platform = self.platform return ''.join([snippet.as_header(current_platform.get_header(self)), template, snippet.as_tailer()]) @@ -684,7 +687,7 @@ class Job: :return: True if succesful, False otherwise :rtype: bool """ - if self.get_platform().get_stat_file(self.name, retries=5): + if self.platform.get_stat_file(self.name, retries=5): start_time = self.check_start_time() else: Log.warning('Could not get start time for {0}. Using current time as an aproximation', self.name) @@ -703,7 +706,7 @@ class Job: :param completed: True if job was completed succesfuly, False otherwise :type completed: bool """ - self.get_platform().get_stat_file(self.name, retries=5) + self.platform.get_stat_file(self.name, retries=5) end_time = self.check_end_time() path = os.path.join(self._tmp_path, self.name + '_TOTAL_STATS') f = open(path, 'a') diff --git a/autosubmit/job/job_list.py b/autosubmit/job/job_list.py index dd4b7e083..cdd36b454 100644 --- a/autosubmit/job/job_list.py +++ b/autosubmit/job/job_list.py @@ -295,7 +295,7 @@ class JobList: :return: completed jobs :rtype: list """ - return [job for job in self._job_list if (platform is None or job.get_platform() is platform) and + return [job for job in self._job_list if (platform is None or job.platform is platform) and job.status == Status.COMPLETED] def get_submitted(self, platform=None): @@ -307,7 +307,7 @@ class JobList: :return: submitted jobs :rtype: list """ - return [job for job in self._job_list if (platform is None or job.get_platform() is platform) and + return [job for job in self._job_list if (platform is None or job.platform is platform) and job.status == Status.SUBMITTED] def get_running(self, platform=None): @@ -319,7 +319,7 @@ class JobList: :return: running jobs :rtype: list """ - return [job for job in self._job_list if (platform is None or job.get_platform() is platform) and + return [job for job in self._job_list if (platform is None or job.platform is platform) and job.status == Status.RUNNING] def get_queuing(self, platform=None): @@ -331,7 +331,7 @@ class JobList: :return: queuedjobs :rtype: list """ - return [job for job in self._job_list if (platform is None or job.get_platform() is platform) and + return [job for job in self._job_list if (platform is None or job.platform is platform) and job.status == Status.QUEUING] def get_failed(self, platform=None): @@ -343,7 +343,7 @@ class JobList: :return: failed jobs :rtype: list """ - return [job for job in self._job_list if (platform is None or job.get_platform() is platform) and + return [job for job in self._job_list if (platform is None or job.platform is platform) and job.status == Status.FAILED] def get_ready(self, platform=None): @@ -355,7 +355,7 @@ class JobList: :return: ready jobs :rtype: list """ - return [job for job in self._job_list if (platform is None or job.get_platform() is platform) and + return [job for job in self._job_list if (platform is None or job.platform is platform) and job.status == Status.READY] def get_waiting(self, platform=None): @@ -367,7 +367,7 @@ class JobList: :return: waiting jobs :rtype: list """ - return [job for job in self._job_list if (platform is None or job.get_platform() is platform) and + return [job for job in self._job_list if (platform is None or job.platform is platform) and job.status == Status.WAITING] def get_unknown(self, platform=None): @@ -379,7 +379,7 @@ class JobList: :return: unknown state jobs :rtype: list """ - return [job for job in self._job_list if (platform is None or job.get_platform() is platform) and + return [job for job in self._job_list if (platform is None or job.platform is platform) and job.status == Status.UNKNOWN] def get_in_queue(self, platform=None): @@ -1010,7 +1010,7 @@ class DicJobs: if job.platform_name is not None: job.platform_name = job.platform_name job.file = self.get_option(section, "FILE", None) - job.set_queue(self.get_option(section, "QUEUE", None)) + job.queue = self.get_option(section, "QUEUE", None) if self.get_option(section, "CHECK", 'True').lower() == 'true': job.check = True else: diff --git a/autosubmit/platforms/lsfplatform.py b/autosubmit/platforms/lsfplatform.py index aed518c08..1e3796606 100644 --- a/autosubmit/platforms/lsfplatform.py +++ b/autosubmit/platforms/lsfplatform.py @@ -119,7 +119,7 @@ class LsfHeader: # noinspection PyMethodMayBeStatic def get_exclusivity(self, job): - if job.get_platform().exclusivity == 'true': + if job.platform.exclusivity == 'true': return "#BSUB -x" else: return "" diff --git a/autosubmit/platforms/platform.py b/autosubmit/platforms/platform.py index 9ea31f8ce..1ac9852fd 100644 --- a/autosubmit/platforms/platform.py +++ b/autosubmit/platforms/platform.py @@ -6,7 +6,7 @@ from autosubmit.config.log import Log from autosubmit.job.job_common import Status -class Platform: +class Platform(object): """ Class to manage the connections to the different platforms. """ @@ -24,6 +24,7 @@ class Platform: self.tmp_path = os.path.join(self.config.LOCAL_ROOT_DIR, self.expid, self.config.LOCAL_TMP_DIR) self._serial_platform = None self._serial_queue = None + self._default_queue = None self.processors_per_node = None self.scratch_free_space = None self.host = '' diff --git a/test/unit/test_dic_jobs.py b/test/unit/test_dic_jobs.py index a9b749c2c..7321a273d 100644 --- a/test/unit/test_dic_jobs.py +++ b/test/unit/test_dic_jobs.py @@ -318,7 +318,7 @@ class TestDicJobs(TestCase): self.assertEquals(Type.BASH, created_job.type) self.assertEquals(platform_name, created_job.platform_name) self.assertEquals(filename, created_job.file) - self.assertEquals(queue, created_job._queue) + self.assertEquals(queue, created_job.queue) self.assertTrue(created_job.check) self.assertEquals(processors, created_job.processors) self.assertEquals(threads, created_job.threads) diff --git a/test/unit/test_job.py b/test/unit/test_job.py index a20b1b0c3..25c0aa6f4 100644 --- a/test/unit/test_job.py +++ b/test/unit/test_job.py @@ -25,6 +25,7 @@ class TestJob(TestCase): self.job_priority = 0 self.job = Job(self.job_name, self.job_id, Status.WAITING, self.job_priority) + self.job.processors = 2 def test_when_the_job_has_more_than_one_processor_returns_the_parallel_platform(self): platform = Platform(self.experiment_id, 'parallel-platform', FakeBasicConfig) @@ -33,7 +34,7 @@ class TestJob(TestCase): self.job._platform = platform self.job.processors = 999 - returned_platform = self.job.get_platform() + returned_platform = self.job.platform self.assertEquals(platform, returned_platform) @@ -44,7 +45,7 @@ class TestJob(TestCase): self.job._platform = platform self.job.processors = 1 - returned_platform = self.job.get_platform() + returned_platform = self.job.platform self.assertEquals('serial-platform', returned_platform) @@ -52,15 +53,15 @@ class TestJob(TestCase): dummy_platform = Platform('whatever', 'rand-name', FakeBasicConfig) self.assertNotEquals(dummy_platform, self.job._platform) - self.job.set_platform(dummy_platform) + self.job.platform = dummy_platform - self.assertEquals(dummy_platform, self.job._platform) + self.assertEquals(dummy_platform, self.job.platform) def test_when_the_job_has_a_queue_returns_that_queue(self): dummy_queue = 'whatever' self.job._queue = dummy_queue - returned_queue = self.job.get_queue() + returned_queue = self.job.queue self.assertEquals(dummy_queue, returned_queue) @@ -68,11 +69,11 @@ class TestJob(TestCase): dummy_queue = 'whatever-parallel' dummy_platform = Platform('whatever', 'rand-name', FakeBasicConfig) dummy_platform.queue = dummy_queue - self.job.set_platform(dummy_platform) + self.job.platform = dummy_platform self.assertIsNone(self.job._queue) - returned_queue = self.job.get_queue() + returned_queue = self.job.queue self.assertIsNotNone(returned_queue) self.assertEquals(dummy_queue, returned_queue) @@ -88,12 +89,12 @@ class TestJob(TestCase): dummy_platform.serial_platform = dummy_serial_platform dummy_platform.queue = parallel_queue - self.job.set_platform(dummy_platform) + self.job.platform = dummy_platform self.job.processors = 1 self.assertIsNone(self.job._queue) - returned_queue = self.job.get_queue() + returned_queue = self.job.queue self.assertIsNotNone(returned_queue) self.assertEquals(serial_queue, returned_queue) @@ -103,9 +104,9 @@ class TestJob(TestCase): dummy_queue = 'whatever' self.assertNotEquals(dummy_queue, self.job._queue) - self.job.set_queue(dummy_queue) + self.job.queue = dummy_queue - self.assertEquals(dummy_queue, self.job._queue) + self.assertEquals(dummy_queue, self.job.queue) def test_that_the_increment_fails_count_only_adds_one(self): initial_fail_count = self.job.fail_count -- GitLab From dd9bb1c0e7e0089e281a8009973d639f5a44059c Mon Sep 17 00:00:00 2001 From: jlope2 Date: Mon, 21 Nov 2016 16:46:46 +0100 Subject: [PATCH 04/25] First implementation of the JobPackage added --- autosubmit/job/job_package.py | 94 +++++++++++++++++++++++++++++++++++ test/unit/test_job_package.py | 60 ++++++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 autosubmit/job/job_package.py create mode 100644 test/unit/test_job_package.py diff --git a/autosubmit/job/job_package.py b/autosubmit/job/job_package.py new file mode 100644 index 000000000..28bb81848 --- /dev/null +++ b/autosubmit/job/job_package.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +# Copyright 2016 Earth Sciences Department, BSC-CNS + +# This file is part of Autosubmit. + +# Autosubmit is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# Autosubmit is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with Autosubmit. If not, see . +try: + # noinspection PyCompatibility + from configparser import SafeConfigParser +except ImportError: + # noinspection PyCompatibility + from ConfigParser import SafeConfigParser + +from autosubmit.job.job_common import Status +from autosubmit.config.log import Log + + +class JobPackage(object): + """ + Class to manage the package of jobs to be submitted by autosubmit + + """ + + def __init__(self, jobs): + self._jobs = jobs + self._job_scripts = {} + try: + self._platform = jobs[0].platform + for job in jobs: + if job.platform != self._platform or job.platform is None: + raise Exception('Only one valid platform per package') + except IndexError: + raise Exception('No jobs given') + + def __len__(self): + return self._jobs.__len__() + + @property + def jobs(self): + """ + Returns the jobs + + :return: jobs + :rtype: List[Job] + """ + return self._jobs + + @property + def platform(self): + """ + Returns the platform + + :return: platform + :rtype: Platform + """ + return self._platform + + def submit(self, configuration, parameters): + for job in self.jobs: + job.update_parameters(configuration, parameters) + self._create_scripts() + self._send_files() + self._do_submission() + + def _create_scripts(self): + for job in self.jobs: + self._job_scripts[job.name] = job.create_script(configuration) + + def _send_files(self): + for job in self.jobs: + self.platform.send_file(self._job_scripts[job.name]) + + def _do_submission(self): + for job in self.jobs: + self.platform.remove_stat_file(job.name) + self.platform.remove_completed_file(job.name) + job.id = self.platform.submit_job(job, self._job_scripts[job.name]) + if job.id is None: + continue + Log.info("{0} submitted", job.name) + job.status = Status.SUBMITTED + job.write_submit_time() \ No newline at end of file diff --git a/test/unit/test_job_package.py b/test/unit/test_job_package.py new file mode 100644 index 000000000..e4557cc31 --- /dev/null +++ b/test/unit/test_job_package.py @@ -0,0 +1,60 @@ +from unittest import TestCase + +import os +from mock import Mock +from mock import patch + +from autosubmit.job.job_package import JobPackage +from autosubmit.job.job import Job +from autosubmit.job.job_common import Status + + +class TestJobPackage(TestCase): + + def setUp(self): + self.platform = Mock() + self.jobs = [Job('dummy1', 0, Status.READY, 0), + Job('dummy2', 0, Status.READY, 0)] + self.jobs[0].platform = self.jobs[1].platform = self.platform + self.job_package = JobPackage(self.jobs) + + def test_job_package_default_init(self): + with self.assertRaises(Exception): + JobPackage([]) + + def test_job_package_different_platforms_init(self): + self.jobs[0].platform = Mock() + self.jobs[1].platform = Mock() + with self.assertRaises(Exception): + JobPackage(this.jobs) + + def test_job_package_none_platforms_init(self): + self.jobs[0].platform = None + self.jobs[1].platform = None + with self.assertRaises(Exception): + JobPackage(this.jobs) + + def test_job_package_length(self): + self.assertEquals(2, len(self.job_package)) + + def test_job_package_jobs_getter(self): + self.assertEquals(self.jobs, self.job_package.jobs) + + def test_job_package_platform_getter(self): + self.assertEquals(self.platform.serial_platform, self.job_package.platform) + + def test_job_package_submission(self): + # arrange + self.job_package._create_scripts = Mock() + self.job_package._send_files = Mock() + self.job_package._do_submission = Mock() + for job in self.jobs: + job.update_parameters = Mock() + # act + self.job_package.submit('fake-config', 'fake-params') + # assert + for job in self.jobs: + job.update_parameters.assert_called_once_with('fake-config', 'fake-params') + self.job_package._create_scripts.is_called_once_with() + self.job_package._send_files.is_called_once_with() + self.job_package._do_submission.is_called_once_with() -- GitLab From 6987674896fb555a2b7b94c2cdc53ebd4ab981c8 Mon Sep 17 00:00:00 2001 From: jlope2 Date: Mon, 21 Nov 2016 17:58:03 +0100 Subject: [PATCH 05/25] Fixed minor in JobPackage --- autosubmit/job/job_package.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/autosubmit/job/job_package.py b/autosubmit/job/job_package.py index 28bb81848..d730ae14c 100644 --- a/autosubmit/job/job_package.py +++ b/autosubmit/job/job_package.py @@ -70,11 +70,11 @@ class JobPackage(object): def submit(self, configuration, parameters): for job in self.jobs: job.update_parameters(configuration, parameters) - self._create_scripts() + self._create_scripts(configuration) self._send_files() self._do_submission() - def _create_scripts(self): + def _create_scripts(self, configuration): for job in self.jobs: self._job_scripts[job.name] = job.create_script(configuration) @@ -91,4 +91,4 @@ class JobPackage(object): continue Log.info("{0} submitted", job.name) job.status = Status.SUBMITTED - job.write_submit_time() \ No newline at end of file + job.write_submit_time() -- GitLab From 713c4a2ece5ab4baecafd5af83f1103a66cfbfc3 Mon Sep 17 00:00:00 2001 From: jlope2 Date: Mon, 21 Nov 2016 17:58:28 +0100 Subject: [PATCH 06/25] Submitter refactored --- autosubmit/autosubmit.py | 53 ++++++++------------------------------ autosubmit/job/job_list.py | 28 ++++++++++++++++++++ 2 files changed, 39 insertions(+), 42 deletions(-) diff --git a/autosubmit/autosubmit.py b/autosubmit/autosubmit.py index f5ceb7c94..71b0a0585 100644 --- a/autosubmit/autosubmit.py +++ b/autosubmit/autosubmit.py @@ -65,6 +65,7 @@ from config.parser_factory import ConfigParserFactory from job.job_common import Status from git.autosubmit_git import AutosubmitGit from job.job_list import JobList +from job.job_package import JobPackage from job.job_list_persistence import JobListPersistenceDb from job.job_list_persistence import JobListPersistencePkl # noinspection PyPackageRequirements @@ -622,9 +623,9 @@ class Autosubmit: if job.platform_name is None: job.platform_name = hpcarch # noinspection PyTypeChecker - job.set_platform(submitter.platforms[job.platform_name.lower()]) + job.platform = submitter.platforms[job.platform_name.lower()] # noinspection PyTypeChecker - platforms_to_test.add(job.get_platform()) + platforms_to_test.add(job.platform) job_list.check_scripts(as_conf) @@ -705,45 +706,13 @@ class Autosubmit: """ save = False for platform in platforms_to_test: - jobs_in_queue = job_list.get_in_queue(platform) - jobs_available = job_list.get_ready(platform) - if len(jobs_available) == 0: - continue - - Log.info("\nJobs ready for {1}: {0}", len(jobs_available), platform.name) - - max_jobs = platform.total_jobs - max_waiting_jobs = platform.max_waiting_jobs - waiting = len(job_list.get_submitted(platform) + job_list.get_queuing(platform)) - available = max_waiting_jobs - waiting - - if min(available, len(jobs_available)) == 0: - Log.debug("Number of jobs ready: {0}", len(jobs_available)) - Log.debug("Number of jobs available: {0}", available) - elif min(available, len(jobs_available)) > 0 and len(job_list.get_in_queue(platform)) <= max_jobs: - Log.info("Jobs to submit: {0}", min(available, len(jobs_available))) - - s = sorted(jobs_available, key=lambda k: k.long_name.split('_')[1][:6]) - list_of_jobs_avail = sorted(s, key=lambda k: k.priority, reverse=True) - - for job in list_of_jobs_avail[0:min(available, len(jobs_available), max_jobs - len(jobs_in_queue))]: - job.update_parameters(as_conf, job_list.parameters) - script_name = job.create_script(as_conf) + for job_package in job_list.get_ready_packages(platform): try: - platform.send_file(script_name) - platform.remove_stat_file(job.name) - platform.remove_completed_file(job.name) - job.id = platform.submit_job(job, script_name) + job_package.submit(as_conf, job_list.parameters) + save = True except Exception: - Log.error("{0} submission failed", job.name) + Log.error("{0} submission failed", platform.name) continue - if job.id is None: - continue - Log.info("{0} submitted", job.name) - # set status to "submitted" - job.status = Status.SUBMITTED - job.write_submit_time() - save = True return save @staticmethod @@ -1028,7 +997,7 @@ class Autosubmit: if job.platform_name is None: job.platform_name = hpcarch # noinspection PyTypeChecker - job.set_platform(platforms[job.platform_name.lower()]) + job.platform = platforms[job.platform_name.lower()] # noinspection PyTypeChecker platforms_to_test.add(platforms[job.platform_name.lower()]) @@ -1043,9 +1012,9 @@ class Autosubmit: if job.platform_name is None: job.platform_name = hpcarch # noinspection PyTypeChecker - job.set_platform(platforms[job.platform_name.lower()]) + job.platform = platforms[job.platform_name.lower()] - if job.get_platform().get_completed_files(job.name, 0): + if job.platform.get_completed_files(job.name, 0): job.status = Status.COMPLETED Log.info("CHANGED job '{0}' status to COMPLETED".format(job.name)) elif job.status != Status.SUSPENDED: @@ -1112,7 +1081,7 @@ class Autosubmit: if job.platform_name is None: job.platform_name = hpcarch # noinspection PyTypeChecker - job.set_platform(submitter.platforms[job.platform_name.lower()]) + job.platform = submitter.platforms[job.platform_name.lower()] job.update_parameters(as_conf, job_list.parameters) return job_list.check_scripts(as_conf) diff --git a/autosubmit/job/job_list.py b/autosubmit/job/job_list.py index cdd36b454..afe37f7d5 100644 --- a/autosubmit/job/job_list.py +++ b/autosubmit/job/job_list.py @@ -32,6 +32,7 @@ from shutil import move from autosubmit.job.job_common import Status, Type from autosubmit.job.job import Job +from autosubmit.job.job_package import JobPackage from autosubmit.config.log import Log from autosubmit.date.chunk_date_lib import date2str, parse_date @@ -744,6 +745,33 @@ class JobList: self.update_genealogy() del self._dic_jobs + def get_ready_packages(self, platform): + # Check there are ready jobs + jobs_available = self.get_ready(platform) + if len(jobs_available) == 0: + return list() + Log.info("\nJobs ready for {1}: {0}", len(jobs_available), platform.name) + # Checking available submission slots + max_waiting_jobs = platform.max_waiting_jobs + waiting_jobs = len(self.get_submitted(platform) + self.get_queuing(platform)) + max_wait_jobs_to_submit = max_waiting_jobs - waiting_jobs + max_jobs_to_submit = platform.total_jobs - len(self.get_in_queue(platform)) + # Logging obtained data + Log.debug("Number of jobs ready: {0}", len(jobs_available)) + Log.debug("Number of jobs available: {0}", max_wait_jobs_to_submit) + Log.info("Jobs to submit: {0}", min(max_wait_jobs_to_submit, len(jobs_available))) + # If can submit jobs + if max_wait_jobs_to_submit > 0 and max_jobs_to_submit > 0: + available_sorted = sorted(jobs_available, key=lambda k: k.long_name.split('_')[1][:6]) + list_of_available = sorted(available_sorted, key=lambda k: k.priority, reverse=True) + num_jobs_to_submit = min(max_wait_jobs_to_submit, len(jobs_available), max_jobs_to_submit) + jobs_to_submit = list_of_available[0:num_jobs_to_submit] + packages_to_submit = list() + for job in jobs_to_submit: + packages_to_submit.append(JobPackage([job])) + return packages_to_submit + return list() # no packages to submit + class DicJobs: """ -- GitLab From da6adab2cd9183d3c11281a8acbd0ae72e002b64 Mon Sep 17 00:00:00 2001 From: jlope2 Date: Mon, 21 Nov 2016 18:51:43 +0100 Subject: [PATCH 07/25] Typo fixed --- autosubmit/job/job_package.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/autosubmit/job/job_package.py b/autosubmit/job/job_package.py index d730ae14c..3581ced35 100644 --- a/autosubmit/job/job_package.py +++ b/autosubmit/job/job_package.py @@ -70,9 +70,9 @@ class JobPackage(object): def submit(self, configuration, parameters): for job in self.jobs: job.update_parameters(configuration, parameters) - self._create_scripts(configuration) - self._send_files() - self._do_submission() + self._create_scripts(configuration) + self._send_files() + self._do_submission() def _create_scripts(self, configuration): for job in self.jobs: -- GitLab From 7b68b3596dd64284f50dba396abcc7c72543f7b6 Mon Sep 17 00:00:00 2001 From: jlope2 Date: Tue, 22 Nov 2016 12:09:12 +0100 Subject: [PATCH 08/25] Setters for job's parents & job's children --- autosubmit/job/job.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/autosubmit/job/job.py b/autosubmit/job/job.py index b98eb97a2..fb9385282 100644 --- a/autosubmit/job/job.py +++ b/autosubmit/job/job.py @@ -117,6 +117,13 @@ class Job(object): """ return self._parents + @parents.setter + def parents(self, parents): + """ + Sets the parents job list + """ + self._parents = parents + @property def platform(self): """ @@ -175,6 +182,13 @@ class Job(object): """ return self._children + @children.setter + def children(self, children): + """ + Sets the children job list + """ + self._children = children + @property def long_name(self): """ -- GitLab From bf42d71361bef23eaff731951e882f9cae4a8501 Mon Sep 17 00:00:00 2001 From: jlope2 Date: Tue, 22 Nov 2016 12:22:08 +0100 Subject: [PATCH 09/25] JobPackage refactor --- autosubmit/autosubmit.py | 1 - autosubmit/job/job_list.py | 4 ++-- autosubmit/job/job_package.py | 23 ++++++++++++++++++++--- test/unit/test_job_package.py | 10 +++++----- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/autosubmit/autosubmit.py b/autosubmit/autosubmit.py index 71b0a0585..6bdecc01a 100644 --- a/autosubmit/autosubmit.py +++ b/autosubmit/autosubmit.py @@ -65,7 +65,6 @@ from config.parser_factory import ConfigParserFactory from job.job_common import Status from git.autosubmit_git import AutosubmitGit from job.job_list import JobList -from job.job_package import JobPackage from job.job_list_persistence import JobListPersistenceDb from job.job_list_persistence import JobListPersistencePkl # noinspection PyPackageRequirements diff --git a/autosubmit/job/job_list.py b/autosubmit/job/job_list.py index afe37f7d5..133dde10e 100644 --- a/autosubmit/job/job_list.py +++ b/autosubmit/job/job_list.py @@ -32,7 +32,7 @@ from shutil import move from autosubmit.job.job_common import Status, Type from autosubmit.job.job import Job -from autosubmit.job.job_package import JobPackage +from autosubmit.job.job_package import JobPackageSimple from autosubmit.config.log import Log from autosubmit.date.chunk_date_lib import date2str, parse_date @@ -768,7 +768,7 @@ class JobList: jobs_to_submit = list_of_available[0:num_jobs_to_submit] packages_to_submit = list() for job in jobs_to_submit: - packages_to_submit.append(JobPackage([job])) + packages_to_submit.append(JobPackageSimple([job])) return packages_to_submit return list() # no packages to submit diff --git a/autosubmit/job/job_package.py b/autosubmit/job/job_package.py index 3581ced35..3bde7b62b 100644 --- a/autosubmit/job/job_package.py +++ b/autosubmit/job/job_package.py @@ -27,15 +27,13 @@ from autosubmit.job.job_common import Status from autosubmit.config.log import Log -class JobPackage(object): +class JobPackageBase(object): """ Class to manage the package of jobs to be submitted by autosubmit - """ def __init__(self, jobs): self._jobs = jobs - self._job_scripts = {} try: self._platform = jobs[0].platform for job in jobs: @@ -74,6 +72,25 @@ class JobPackage(object): self._send_files() self._do_submission() + def _create_scripts(self, configuration): + raise Exception('Not implemented') + + def _send_files(self): + raise Exception('Not implemented') + + def _do_submission(self): + raise Exception('Not implemented') + + +class JobPackageSimple(JobPackageBase): + """ + Class to manage the package of jobs to be submitted by autosubmit + """ + + def __init__(self, jobs): + self._job_scripts = {} + super(JobPackageSimple, self).__init__(jobs) + def _create_scripts(self, configuration): for job in self.jobs: self._job_scripts[job.name] = job.create_script(configuration) diff --git a/test/unit/test_job_package.py b/test/unit/test_job_package.py index e4557cc31..6e530ae31 100644 --- a/test/unit/test_job_package.py +++ b/test/unit/test_job_package.py @@ -4,7 +4,7 @@ import os from mock import Mock from mock import patch -from autosubmit.job.job_package import JobPackage +from autosubmit.job.job_package import JobPackageSimple from autosubmit.job.job import Job from autosubmit.job.job_common import Status @@ -16,23 +16,23 @@ class TestJobPackage(TestCase): self.jobs = [Job('dummy1', 0, Status.READY, 0), Job('dummy2', 0, Status.READY, 0)] self.jobs[0].platform = self.jobs[1].platform = self.platform - self.job_package = JobPackage(self.jobs) + self.job_package = JobPackageSimple(self.jobs) def test_job_package_default_init(self): with self.assertRaises(Exception): - JobPackage([]) + JobPackageSimple([]) def test_job_package_different_platforms_init(self): self.jobs[0].platform = Mock() self.jobs[1].platform = Mock() with self.assertRaises(Exception): - JobPackage(this.jobs) + JobPackageSimple(this.jobs) def test_job_package_none_platforms_init(self): self.jobs[0].platform = None self.jobs[1].platform = None with self.assertRaises(Exception): - JobPackage(this.jobs) + JobPackageSimple(this.jobs) def test_job_package_length(self): self.assertEquals(2, len(self.job_package)) -- GitLab From 6f84e3d09a71512dcd6c39e9c3dbc4a2f770879d Mon Sep 17 00:00:00 2001 From: jlope2 Date: Tue, 22 Nov 2016 18:23:39 +0100 Subject: [PATCH 10/25] Minor in regression tests --- test/regression/test_mn_with_paramiko/conf/jobs.conf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/regression/test_mn_with_paramiko/conf/jobs.conf b/test/regression/test_mn_with_paramiko/conf/jobs.conf index 0f96a8293..d9d2a14ef 100644 --- a/test/regression/test_mn_with_paramiko/conf/jobs.conf +++ b/test/regression/test_mn_with_paramiko/conf/jobs.conf @@ -26,4 +26,5 @@ RUNNING = chunk WALLCLOCK = 00:10 TASKS = 16 PROCESSORS = 32 -SCRATCH_FREE_SPACE = 15 \ No newline at end of file +SCRATCH_FREE_SPACE = 15 +DEPENDENCIES = WITH_FREE_SCRATCH-1 \ No newline at end of file -- GitLab From cdc85c625306d0cd0ef2bd66d68c64efc8b6e65c Mon Sep 17 00:00:00 2001 From: jlope2 Date: Wed, 23 Nov 2016 13:08:03 +0100 Subject: [PATCH 11/25] First implementation of JobPackages based on arrays --- autosubmit/job/job_list.py | 4 +++ autosubmit/job/job_package.py | 58 +++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/autosubmit/job/job_list.py b/autosubmit/job/job_list.py index 133dde10e..6a315c6f8 100644 --- a/autosubmit/job/job_list.py +++ b/autosubmit/job/job_list.py @@ -33,6 +33,7 @@ from shutil import move from autosubmit.job.job_common import Status, Type from autosubmit.job.job import Job from autosubmit.job.job_package import JobPackageSimple +from autosubmit.job.job_package import JobPackageArray from autosubmit.config.log import Log from autosubmit.date.chunk_date_lib import date2str, parse_date @@ -767,6 +768,9 @@ class JobList: num_jobs_to_submit = min(max_wait_jobs_to_submit, len(jobs_available), max_jobs_to_submit) jobs_to_submit = list_of_available[0:num_jobs_to_submit] packages_to_submit = list() + if platform.name == 'marenostrum3': + packages_to_submit.append(JobPackageArray(jobs_to_submit)) + return packages_to_submit for job in jobs_to_submit: packages_to_submit.append(JobPackageSimple([job])) return packages_to_submit diff --git a/autosubmit/job/job_package.py b/autosubmit/job/job_package.py index 3bde7b62b..3db995419 100644 --- a/autosubmit/job/job_package.py +++ b/autosubmit/job/job_package.py @@ -23,6 +23,8 @@ except ImportError: # noinspection PyCompatibility from ConfigParser import SafeConfigParser +import time +import os from autosubmit.job.job_common import Status from autosubmit.config.log import Log @@ -35,6 +37,7 @@ class JobPackageBase(object): def __init__(self, jobs): self._jobs = jobs try: + self._tmp_path = jobs[0]._tmp_path self._platform = jobs[0].platform for job in jobs: if job.platform != self._platform or job.platform is None: @@ -109,3 +112,58 @@ class JobPackageSimple(JobPackageBase): Log.info("{0} submitted", job.name) job.status = Status.SUBMITTED job.write_submit_time() + + +class JobPackageArray(JobPackageBase): + """ + Class to manage the package of jobs to be submitted by autosubmit + """ + + def __init__(self, jobs): + self._job_inputs = {} + self._job_scripts = {} + self._common_script = None + super(JobPackageArray, self).__init__(jobs) + + def _create_scripts(self, configuration): + timestamp = str(int(time.time())) + for i in range(1, len(self.jobs) + 1): + self._job_scripts[self.jobs[i - 1].name] = self.jobs[i - 1].create_script(configuration) + self._job_inputs[self.jobs[i - 1].name] = self._create_i_input(timestamp, i) + self._common_script = self._create_common_script(timestamp) + + def _create_i_input(self, filename, index): + filename += '.{0}'.format(index) + input_content = self._job_scripts[self.jobs[index - 1].name] + open(os.path.join(self._tmp_path, filename), 'w').write(input_content) + os.chmod(os.path.join(self._tmp_path, filename), 0o775) + return filename + + def _create_common_script(self, filename): + filename += '.cmd' + script_content = '' + open(os.path.join(self._tmp_path, filename), 'w').write(script_content) + os.chmod(os.path.join(self._tmp_path, filename), 0o775) + return filename + + def _send_files(self): + for job in self.jobs: + self.platform.send_file(self._job_scripts[job.name]) + self.platform.send_file(self._job_inputs[job.name]) + self.platform.send_file(self._common_script) + + def _do_submission(self): + for job in self.jobs: + self.platform.remove_stat_file(job.name) + self.platform.remove_completed_file(job.name) + + package_id = self.platform.submit_job(None, self._common_script) + + if package_id is None: + raise Exception('Submission failed') + + for i in range(1, len(self.jobs) + 1): + Log.info("{0} submitted", self.jobs[i - 1].name) + self.jobs[i - 1].id = str(package_id) + '[{0}]'.format(index) + self.jobs[i - 1].job.status = Status.SUBMITTED + self.jobs[i - 1].job.write_submit_time() -- GitLab From 79ed74e1cb9471335c04df27cf021a51aeb3204b Mon Sep 17 00:00:00 2001 From: jlope2 Date: Wed, 23 Nov 2016 18:01:33 +0100 Subject: [PATCH 12/25] Allowing job ids being strings (for arrays) --- autosubmit/platforms/paramiko_platform.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/autosubmit/platforms/paramiko_platform.py b/autosubmit/platforms/paramiko_platform.py index d22f9c1b5..e2660b9bf 100644 --- a/autosubmit/platforms/paramiko_platform.py +++ b/autosubmit/platforms/paramiko_platform.py @@ -184,9 +184,9 @@ class ParamikoPlatform(Platform): """ job_status = Status.UNKNOWN - if type(job_id) is not int: + if type(job_id) is not int and type(job_id) is not str: # URi: logger - Log.error('check_job() The job id ({0}) is not an integer.', job_id) + Log.error('check_job() The job id ({0}) is not an integer neither a string.', job_id) # URi: value ? return job_status -- GitLab From 80ca7c4efc418067859dd2c26aa66970c481376a Mon Sep 17 00:00:00 2001 From: jlope2 Date: Thu, 24 Nov 2016 11:34:59 +0100 Subject: [PATCH 13/25] Determining if the given platform allow scheduler arrays --- autosubmit/job/job_list.py | 4 +++- autosubmit/platforms/lsfplatform.py | 1 + autosubmit/platforms/platform.py | 5 +++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/autosubmit/job/job_list.py b/autosubmit/job/job_list.py index 6a315c6f8..e012fbf9d 100644 --- a/autosubmit/job/job_list.py +++ b/autosubmit/job/job_list.py @@ -767,8 +767,10 @@ class JobList: list_of_available = sorted(available_sorted, key=lambda k: k.priority, reverse=True) num_jobs_to_submit = min(max_wait_jobs_to_submit, len(jobs_available), max_jobs_to_submit) jobs_to_submit = list_of_available[0:num_jobs_to_submit] + + # Generating Job Packages packages_to_submit = list() - if platform.name == 'marenostrum3': + if platform.allow_arrays: packages_to_submit.append(JobPackageArray(jobs_to_submit)) return packages_to_submit for job in jobs_to_submit: diff --git a/autosubmit/platforms/lsfplatform.py b/autosubmit/platforms/lsfplatform.py index 1e3796606..9eff05469 100644 --- a/autosubmit/platforms/lsfplatform.py +++ b/autosubmit/platforms/lsfplatform.py @@ -37,6 +37,7 @@ class LsfPlatform(ParamikoPlatform): self.job_status['RUNNING'] = ['RUN'] self.job_status['QUEUING'] = ['PEND', 'FW_PEND'] self.job_status['FAILED'] = ['SSUSP', 'USUSP', 'EXIT'] + self._allow_arrays = True self.update_cmds() def update_cmds(self): diff --git a/autosubmit/platforms/platform.py b/autosubmit/platforms/platform.py index 1ac9852fd..505bbe0c0 100644 --- a/autosubmit/platforms/platform.py +++ b/autosubmit/platforms/platform.py @@ -39,6 +39,7 @@ class Platform(object): self.service = None self.scheduler = None self.directory = None + self._allow_arrays = False @property def serial_platform(self): @@ -85,6 +86,10 @@ class Platform(object): def serial_queue(self, value): self._serial_queue = value + @property + def allow_arrays(self): + return self._allow_arrays is True + def add_parameters(self, parameters, main_hpc=False): """ Add parameters for the current platform to the given parameters list -- GitLab From f575951184aa64128bf0645721d8260879b10fda Mon Sep 17 00:00:00 2001 From: jlope2 Date: Thu, 24 Nov 2016 12:34:11 +0100 Subject: [PATCH 14/25] LSF Arrays header has been added --- autosubmit/platforms/lsfplatform.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/autosubmit/platforms/lsfplatform.py b/autosubmit/platforms/lsfplatform.py index 9eff05469..a3751cd92 100644 --- a/autosubmit/platforms/lsfplatform.py +++ b/autosubmit/platforms/lsfplatform.py @@ -125,6 +125,27 @@ class LsfHeader: else: return "" + @classmethod + def array_header(cls, filename, array_id, wallclock, num_processors): + return textwrap.dedent("""\ + ############################################################################### + # {0} + ############################################################################### + # + # + #BSUB -J {0}{1} + #BSUB -oo {0}.%I.out + #BSUB -eo {0}.%I.err + #BSUB -W {2} + #BSUB -n {3} + # + ############################################################################### + + SCRIPT=$(cat {0}.$LSB_JOBINDEX | awk 'NR==1') + chmod +x $SCRIPT + ./$SCRIPT + """.format(filename, array_id, wallclock, num_processors)) + SERIAL = textwrap.dedent("""\ ############################################################################### # %TASKTYPE% %EXPID% EXPERIMENT -- GitLab From d1937de6bf7556b3ed18516bc83704e8a5de8e39 Mon Sep 17 00:00:00 2001 From: jlope2 Date: Thu, 24 Nov 2016 12:35:10 +0100 Subject: [PATCH 15/25] Alpha implementation of the JobPackage for LSF Arrays --- autosubmit/job/job_package.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/autosubmit/job/job_package.py b/autosubmit/job/job_package.py index 3db995419..39021f6c1 100644 --- a/autosubmit/job/job_package.py +++ b/autosubmit/job/job_package.py @@ -123,6 +123,14 @@ class JobPackageArray(JobPackageBase): self._job_inputs = {} self._job_scripts = {} self._common_script = None + self._array_size_id = "[1-" + str(len(jobs)) + "]" + self._wallclock = '00:00' + self._num_processors = 1 + for job in jobs: + if job.wallclock > self._wallclock: + self._wallclock = job.wallclock + if job.processors > self._num_processors: + self._num_processors = job.processors super(JobPackageArray, self).__init__(jobs) def _create_scripts(self, configuration): @@ -140,8 +148,9 @@ class JobPackageArray(JobPackageBase): return filename def _create_common_script(self, filename): + script_content = self.platform.header.array_header(filename, self._array_size_id, self._wallclock, + self._num_processors) filename += '.cmd' - script_content = '' open(os.path.join(self._tmp_path, filename), 'w').write(script_content) os.chmod(os.path.join(self._tmp_path, filename), 0o775) return filename @@ -164,6 +173,6 @@ class JobPackageArray(JobPackageBase): for i in range(1, len(self.jobs) + 1): Log.info("{0} submitted", self.jobs[i - 1].name) - self.jobs[i - 1].id = str(package_id) + '[{0}]'.format(index) - self.jobs[i - 1].job.status = Status.SUBMITTED - self.jobs[i - 1].job.write_submit_time() + self.jobs[i - 1].id = str(package_id) + '[{0}]'.format(i) + self.jobs[i - 1].status = Status.SUBMITTED + self.jobs[i - 1].write_submit_time() -- GitLab From 7452e957bd9df4e71c841df6d981329a178488a0 Mon Sep 17 00:00:00 2001 From: jlope2 Date: Thu, 24 Nov 2016 18:14:11 +0100 Subject: [PATCH 16/25] Jobs logs refactor --- autosubmit/job/job.py | 32 +++++++++++++++++------ autosubmit/platforms/locplatform.py | 8 +++--- autosubmit/platforms/paramiko_platform.py | 13 ++++----- autosubmit/platforms/platform.py | 11 ++++---- autosubmit/platforms/saga_platform.py | 9 ++++--- 5 files changed, 44 insertions(+), 29 deletions(-) diff --git a/autosubmit/job/job.py b/autosubmit/job/job.py index fb9385282..e75100abf 100644 --- a/autosubmit/job/job.py +++ b/autosubmit/job/job.py @@ -73,8 +73,8 @@ class Job(object): self.id = jobid self.file = None - self.out_filename = '' - self.err_filename = '' + self._local_logs = ('', '') + self._remote_logs = ('', '') self.status = status self.priority = priority self._parents = set() @@ -212,6 +212,22 @@ class Job(object): """ self._long_name = value + @property + def local_logs(self): + return self._local_logs + + @local_logs.setter + def local_logs(self, value): + self.local_logs = value + + @property + def remote_logs(self): + return self._remote_logs + + @remote_logs.setter + def remote_logs(self, value): + self._remote_logs = value + def log_job(self): """ Prints job information in log @@ -350,10 +366,10 @@ class Job(object): :return: list of values in column index position :rtype: list[datetime.datetime] """ - logname = os.path.join(self._tmp_path, self.name + '_TOTAL_STATS') + log_name = os.path.join(self._tmp_path, self.name + '_TOTAL_STATS') lst = [] - if os.path.exists(logname): - f = open(logname) + if os.path.exists(log_name): + f = open(log_name) lines = f.readlines() for line in lines: fields = line.split() @@ -448,7 +464,7 @@ class Job(object): if self.status in [Status.COMPLETED, Status.FAILED, Status.UNKNOWN]: self.write_end_time(self.status == Status.COMPLETED) if copy_remote_logs: - self.platform.get_logs_files(self.expid, self.out_filename, self.err_filename) + self.platform.get_logs_files(self.expid, self.remote_logs) return self.status def check_completion(self, default_status=Status.FAILED): @@ -458,8 +474,8 @@ class Job(object): :param default_status: status to set if job is not completed. By default is FAILED :type default_status: Status """ - logname = os.path.join(self._tmp_path, self.name + '_COMPLETED') - if os.path.exists(logname): + log_name = os.path.join(self._tmp_path, self.name + '_COMPLETED') + if os.path.exists(log_name): self.status = Status.COMPLETED else: Log.warning("Job {0} seemed to be completed but there is no COMPLETED file", self.name) diff --git a/autosubmit/platforms/locplatform.py b/autosubmit/platforms/locplatform.py index ff69d2bf2..b4bca2412 100644 --- a/autosubmit/platforms/locplatform.py +++ b/autosubmit/platforms/locplatform.py @@ -139,17 +139,15 @@ class LocalPlatform(ParamikoPlatform): def get_ssh_output(self): return self._ssh_output - def get_logs_files(self, exp_id, job_out_filename, job_err_filename): + def get_logs_files(self, exp_id, remote_logs): """ Overriding the parent's implementation. Do nothing because the log files are already in the local platform (redundancy). :param exp_id: experiment id :type exp_id: str - :param job_out_filename: name of the out file - :type job_out_filename: str - :param job_err_filename: name of the err file - :type job_err_filename: str + :param remote_logs: names of the log files + :type remote_logs: (str, str) """ return diff --git a/autosubmit/platforms/paramiko_platform.py b/autosubmit/platforms/paramiko_platform.py index e2660b9bf..5a2bca45b 100644 --- a/autosubmit/platforms/paramiko_platform.py +++ b/autosubmit/platforms/paramiko_platform.py @@ -318,8 +318,8 @@ class ParamikoPlatform(Platform): executable = 'Rscript' return 'nohup ' + executable + ' {0} > {1} 2> {2} & echo $!'.format( os.path.join(self.remote_log_dir, job_script), - os.path.join(self.remote_log_dir, job.out_filename), - os.path.join(self.remote_log_dir, job.err_filename) + os.path.join(self.remote_log_dir, job.remote_logs[0]), + os.path.join(self.remote_log_dir, job.remote_logs[1]) ) @staticmethod @@ -359,10 +359,11 @@ class ParamikoPlatform(Platform): header = self.header.SERIAL str_datetime = date2str(datetime.datetime.now(), 'S') - job.out_filename = "{0}.{1}.out".format(job.name, str_datetime) - job.err_filename = "{0}.{1}.err".format(job.name, str_datetime) - header = header.replace('%OUT_LOG_DIRECTIVE%', job.out_filename) - header = header.replace('%ERR_LOG_DIRECTIVE%', job.err_filename) + out_filename = "{0}.{1}.out".format(job.name, str_datetime) + err_filename = "{0}.{1}.err".format(job.name, str_datetime) + job.remote_logs = (out_filename, err_filename) + header = header.replace('%OUT_LOG_DIRECTIVE%', out_filename) + header = header.replace('%ERR_LOG_DIRECTIVE%', err_filename) if hasattr(self.header, 'get_queue_directive'): header = header.replace('%QUEUE_DIRECTIVE%', self.header.get_queue_directive(job)) diff --git a/autosubmit/platforms/platform.py b/autosubmit/platforms/platform.py index 505bbe0c0..1293bbd79 100644 --- a/autosubmit/platforms/platform.py +++ b/autosubmit/platforms/platform.py @@ -168,17 +168,16 @@ class Platform(object): """ raise NotImplementedError - def get_logs_files(self, exp_id, job_out_filename, job_err_filename): + def get_logs_files(self, exp_id, remote_logs): """ Get the given LOGS files - + :param exp_id: experiment id :type exp_id: str - :param job_out_filename: name of the out file - :type job_out_filename: str - :param job_err_filename: name of the err file - :type job_err_filename: str + :param remote_logs: names of the log files + :type remote_logs: (str, str) """ + (job_out_filename, job_err_filename) = remote_logs self.get_files([job_out_filename, job_err_filename], False, 'LOG_{0}'.format(exp_id)) def get_completed_files(self, job_name, retries=5): diff --git a/autosubmit/platforms/saga_platform.py b/autosubmit/platforms/saga_platform.py index 85b20b4d4..d0c83590d 100644 --- a/autosubmit/platforms/saga_platform.py +++ b/autosubmit/platforms/saga_platform.py @@ -230,10 +230,11 @@ class SagaPlatform(Platform): jd.working_directory = self.get_files_path() str_datetime = date2str(datetime.datetime.now(), 'S') - job.out_filename = "{0}.{1}.out".format(job.name, str_datetime) - job.err_filename = "{0}.{1}.err".format(job.name, str_datetime) - jd.output = job.out_filename - jd.error = job.err_filename + out_filename = "{0}.{1}.out".format(job.name, str_datetime) + err_filename = "{0}.{1}.err".format(job.name, str_datetime) + job.remote_logs = (out_filename, err_filename) + jd.output = out_filename + jd.error = err_filename self.add_attribute(jd, 'Name', job.name) -- GitLab From aa6527ed3bb76935249961580e5d4b59c061f6fe Mon Sep 17 00:00:00 2001 From: jlope2 Date: Fri, 25 Nov 2016 17:02:00 +0100 Subject: [PATCH 17/25] Renaming remote logs from job packages --- autosubmit/job/job.py | 9 +++++++- autosubmit/job/job_package.py | 1 + autosubmit/platforms/paramiko_platform.py | 26 +++++++++++++++++++++-- autosubmit/platforms/platform.py | 10 +++++++++ autosubmit/platforms/saga_platform.py | 2 +- 5 files changed, 44 insertions(+), 4 deletions(-) diff --git a/autosubmit/job/job.py b/autosubmit/job/job.py index e75100abf..a3a6afb43 100644 --- a/autosubmit/job/job.py +++ b/autosubmit/job/job.py @@ -218,7 +218,8 @@ class Job(object): @local_logs.setter def local_logs(self, value): - self.local_logs = value + self._local_logs = value + self._remote_logs = value @property def remote_logs(self): @@ -463,6 +464,8 @@ class Job(object): self.write_start_time() if self.status in [Status.COMPLETED, Status.FAILED, Status.UNKNOWN]: self.write_end_time(self.status == Status.COMPLETED) + if self.local_logs != self.remote_logs: + self.synchronize_logs() # unifying names for log files if copy_remote_logs: self.platform.get_logs_files(self.expid, self.remote_logs) return self.status @@ -810,3 +813,7 @@ class Job(object): if self.is_ancestor(parent): parent.children.remove(self) self.parents.remove(parent) + + def synchronize_logs(self): + self.platform.move_file(self.remote_logs[0], self.local_logs[0]) # .out + self.platform.move_file(self.remote_logs[1], self.local_logs[1]) # .err diff --git a/autosubmit/job/job_package.py b/autosubmit/job/job_package.py index 39021f6c1..2bc610bcd 100644 --- a/autosubmit/job/job_package.py +++ b/autosubmit/job/job_package.py @@ -138,6 +138,7 @@ class JobPackageArray(JobPackageBase): for i in range(1, len(self.jobs) + 1): self._job_scripts[self.jobs[i - 1].name] = self.jobs[i - 1].create_script(configuration) self._job_inputs[self.jobs[i - 1].name] = self._create_i_input(timestamp, i) + self.jobs[i - 1].remote_logs = (filename + ".{0}.out".format(i), filename + ".{0}.err".format(i)) self._common_script = self._create_common_script(timestamp) def _create_i_input(self, filename, index): diff --git a/autosubmit/platforms/paramiko_platform.py b/autosubmit/platforms/paramiko_platform.py index 5a2bca45b..6f7f86cb9 100644 --- a/autosubmit/platforms/paramiko_platform.py +++ b/autosubmit/platforms/paramiko_platform.py @@ -136,7 +136,7 @@ class ParamikoPlatform(Platform): :param filename: file name :type filename: str - :return: True if succesful or file does no exists + :return: True if successful or file does no exists :rtype: bool """ if self._ssh is None: @@ -152,6 +152,28 @@ class ParamikoPlatform(Platform): Log.debug('Could not remove file {0}'.format(os.path.join(self.get_files_path(), filename))) return False + def move_file(self, src, dest): + """ + Moves a file on the platform + :param src: source name + :type src: str + :param dest: destination name + :type dest: str + """ + if self._ssh is None: + if not self.connect(): + return None + + try: + ftp = self._ssh.open_sftp() + ftp.rename(os.path.join(self.get_files_path(), src), os.path.join(self.get_files_path(), dest)) + ftp.close() + return True + except BaseException: + Log.debug('Could not move (rename) file {0} to {1}'.format(os.path.join(self.get_files_path(), src), + os.path.join(self.get_files_path(), dest))) + return False + def submit_job(self, job, script_name): """ Submit a job from a given job object. @@ -361,7 +383,7 @@ class ParamikoPlatform(Platform): str_datetime = date2str(datetime.datetime.now(), 'S') out_filename = "{0}.{1}.out".format(job.name, str_datetime) err_filename = "{0}.{1}.err".format(job.name, str_datetime) - job.remote_logs = (out_filename, err_filename) + job.local_logs = (out_filename, err_filename) header = header.replace('%OUT_LOG_DIRECTIVE%', out_filename) header = header.replace('%ERR_LOG_DIRECTIVE%', err_filename) diff --git a/autosubmit/platforms/platform.py b/autosubmit/platforms/platform.py index 1293bbd79..ea3290cc9 100644 --- a/autosubmit/platforms/platform.py +++ b/autosubmit/platforms/platform.py @@ -126,6 +126,16 @@ class Platform(object): """ raise NotImplementedError + def move_file(self, src, dest): + """ + Moves a file on the platform + :param src: source name + :type src: str + :param dest: destination name + :type dest: str + """ + raise NotImplementedError + def get_file(self, filename, must_exist=True, relative_path=''): """ Copies a file from the current platform to experiment's tmp folder diff --git a/autosubmit/platforms/saga_platform.py b/autosubmit/platforms/saga_platform.py index d0c83590d..eeec8f6ec 100644 --- a/autosubmit/platforms/saga_platform.py +++ b/autosubmit/platforms/saga_platform.py @@ -232,7 +232,7 @@ class SagaPlatform(Platform): str_datetime = date2str(datetime.datetime.now(), 'S') out_filename = "{0}.{1}.out".format(job.name, str_datetime) err_filename = "{0}.{1}.err".format(job.name, str_datetime) - job.remote_logs = (out_filename, err_filename) + job.local_logs = (out_filename, err_filename) jd.output = out_filename jd.error = err_filename -- GitLab From 37a4bc89d35c184a0cda24fd0ad615316d889a33 Mon Sep 17 00:00:00 2001 From: jlope2 Date: Fri, 25 Nov 2016 18:30:37 +0100 Subject: [PATCH 18/25] Minors fixed --- autosubmit/job/job.py | 1 + autosubmit/job/job_package.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/autosubmit/job/job.py b/autosubmit/job/job.py index a3a6afb43..a213ecd06 100644 --- a/autosubmit/job/job.py +++ b/autosubmit/job/job.py @@ -817,3 +817,4 @@ class Job(object): def synchronize_logs(self): self.platform.move_file(self.remote_logs[0], self.local_logs[0]) # .out self.platform.move_file(self.remote_logs[1], self.local_logs[1]) # .err + self.remote_logs = self.local_logs diff --git a/autosubmit/job/job_package.py b/autosubmit/job/job_package.py index 2bc610bcd..58c7d84a9 100644 --- a/autosubmit/job/job_package.py +++ b/autosubmit/job/job_package.py @@ -138,7 +138,7 @@ class JobPackageArray(JobPackageBase): for i in range(1, len(self.jobs) + 1): self._job_scripts[self.jobs[i - 1].name] = self.jobs[i - 1].create_script(configuration) self._job_inputs[self.jobs[i - 1].name] = self._create_i_input(timestamp, i) - self.jobs[i - 1].remote_logs = (filename + ".{0}.out".format(i), filename + ".{0}.err".format(i)) + self.jobs[i - 1].remote_logs = (timestamp + ".{0}.out".format(i), timestamp + ".{0}.err".format(i)) self._common_script = self._create_common_script(timestamp) def _create_i_input(self, filename, index): -- GitLab From 32db4bedb5c70170601559c24a8868aff0151f08 Mon Sep 17 00:00:00 2001 From: jlope2 Date: Mon, 28 Nov 2016 13:21:15 +0100 Subject: [PATCH 19/25] Loading log files from persistence --- autosubmit/job/job.py | 4 ++-- autosubmit/job/job_list.py | 2 ++ autosubmit/job/job_list_persistence.py | 16 ++++++++++------ 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/autosubmit/job/job.py b/autosubmit/job/job.py index a213ecd06..5181d240d 100644 --- a/autosubmit/job/job.py +++ b/autosubmit/job/job.py @@ -50,7 +50,7 @@ class Job(object): def __str__(self): return "{0} STATUS: {1}".format(self.name, self.status) - def __init__(self, name, jobid, status, priority): + def __init__(self, name, job_id, status, priority): self._platform = None self._queue = None self.platform_name = None @@ -71,7 +71,7 @@ class Job(object): self.type = Type.BASH self.scratch_free_space = None - self.id = jobid + self.id = job_id self.file = None self._local_logs = ('', '') self._remote_logs = ('', '') diff --git a/autosubmit/job/job_list.py b/autosubmit/job/job_list.py index e012fbf9d..84f823254 100644 --- a/autosubmit/job/job_list.py +++ b/autosubmit/job/job_list.py @@ -1020,6 +1020,8 @@ class DicJobs: name += "_" + section if name in jobs_data: job = Job(name, jobs_data[name][1], jobs_data[name][2], priority) + job.local_logs = jobs_data[name][8] + job.remote_logs = jobs_data[name][9] else: job = Job(name, 0, Status.WAITING, priority) job.section = section diff --git a/autosubmit/job/job_list_persistence.py b/autosubmit/job/job_list_persistence.py index a718325f6..cba5ce02c 100644 --- a/autosubmit/job/job_list_persistence.py +++ b/autosubmit/job/job_list_persistence.py @@ -86,8 +86,9 @@ class JobListPersistencePkl(JobListPersistence): fd = open(path, 'w') setrecursionlimit(50000) Log.debug("Saving JobList: " + path) - jobs_data = [(job.name, job.id, job.status, job.priority, job.section, job.date, job.member, job.chunk) for job - in job_list] + jobs_data = [(job.name, job.id, job.status, + job.priority, job.section, job.date, + job.member, job.chunk, job.local_logs[0], job.local_logs[1]) for job in job_list] pickle.dump(jobs_data, fd) Log.debug('Job list saved') @@ -98,9 +99,11 @@ class JobListPersistenceDb(JobListPersistence): """ - VERSION = 1 + VERSION = 2 JOB_LIST_TABLE = 'job_list' - TABLE_FIELDS = ['name', 'id', 'status', 'priority', 'section', 'date', 'member', 'chunk'] + TABLE_FIELDS = ['name', 'id', 'status', 'priority', + 'section', 'date', 'member', 'chunk', + 'out_filename', 'err_filename'] def __init__(self, persistence_path, persistence_file): self.db_manager = DbManager(persistence_path, persistence_file, self.VERSION) @@ -123,8 +126,9 @@ class JobListPersistenceDb(JobListPersistence): """ self._reset_table() - jobs_data = [(job.name, job.id, job.status, job.priority, job.section, job.date, job.member, job.chunk) for job - in job_list] + jobs_data = [(job.name, job.id, job.status, + job.priority, job.section, job.date, + job.member, job.chunk, job.local_logs[0], job.local_logs[1]) for job in job_list] self.db_manager.insertMany(self.JOB_LIST_TABLE, jobs_data) def _reset_table(self): -- GitLab From 78c2850a04fc0d22874362029ab342086e6df359 Mon Sep 17 00:00:00 2001 From: jlope2 Date: Mon, 28 Nov 2016 16:04:48 +0100 Subject: [PATCH 20/25] Fixed loading log files from persistence --- autosubmit/job/job_list.py | 4 ++-- autosubmit/job/job_list_persistence.py | 13 +++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/autosubmit/job/job_list.py b/autosubmit/job/job_list.py index 84f823254..e322d3465 100644 --- a/autosubmit/job/job_list.py +++ b/autosubmit/job/job_list.py @@ -1020,8 +1020,8 @@ class DicJobs: name += "_" + section if name in jobs_data: job = Job(name, jobs_data[name][1], jobs_data[name][2], priority) - job.local_logs = jobs_data[name][8] - job.remote_logs = jobs_data[name][9] + job.local_logs = (jobs_data[name][8], jobs_data[name][9]) + job.remote_logs = (jobs_data[name][10], jobs_data[name][11]) else: job = Job(name, 0, Status.WAITING, priority) job.section = section diff --git a/autosubmit/job/job_list_persistence.py b/autosubmit/job/job_list_persistence.py index cba5ce02c..23008451c 100644 --- a/autosubmit/job/job_list_persistence.py +++ b/autosubmit/job/job_list_persistence.py @@ -88,7 +88,9 @@ class JobListPersistencePkl(JobListPersistence): Log.debug("Saving JobList: " + path) jobs_data = [(job.name, job.id, job.status, job.priority, job.section, job.date, - job.member, job.chunk, job.local_logs[0], job.local_logs[1]) for job in job_list] + job.member, job.chunk, + job.local_logs[0], job.local_logs[1], + job.remote_logs[0], job.remote_logs[1]) for job in job_list] pickle.dump(jobs_data, fd) Log.debug('Job list saved') @@ -99,11 +101,12 @@ class JobListPersistenceDb(JobListPersistence): """ - VERSION = 2 + VERSION = 3 JOB_LIST_TABLE = 'job_list' TABLE_FIELDS = ['name', 'id', 'status', 'priority', 'section', 'date', 'member', 'chunk', - 'out_filename', 'err_filename'] + 'local_out', 'local_err' + 'remote_out', 'remote_err'] def __init__(self, persistence_path, persistence_file): self.db_manager = DbManager(persistence_path, persistence_file, self.VERSION) @@ -128,7 +131,9 @@ class JobListPersistenceDb(JobListPersistence): self._reset_table() jobs_data = [(job.name, job.id, job.status, job.priority, job.section, job.date, - job.member, job.chunk, job.local_logs[0], job.local_logs[1]) for job in job_list] + job.member, job.chunk, + job.local_logs[0], job.local_logs[1], + job.remote_logs[0], job.remote_logs[1]) for job in job_list] self.db_manager.insertMany(self.JOB_LIST_TABLE, jobs_data) def _reset_table(self): -- GitLab From b0ce098c2f3e09add0c766bfd99e7a754816073b Mon Sep 17 00:00:00 2001 From: jlope2 Date: Mon, 28 Nov 2016 18:17:22 +0100 Subject: [PATCH 21/25] Filter job packages by section --- autosubmit/job/job_list.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/autosubmit/job/job_list.py b/autosubmit/job/job_list.py index e322d3465..48515eac7 100644 --- a/autosubmit/job/job_list.py +++ b/autosubmit/job/job_list.py @@ -767,17 +767,33 @@ class JobList: list_of_available = sorted(available_sorted, key=lambda k: k.priority, reverse=True) num_jobs_to_submit = min(max_wait_jobs_to_submit, len(jobs_available), max_jobs_to_submit) jobs_to_submit = list_of_available[0:num_jobs_to_submit] - - # Generating Job Packages + jobs_to_submit_by_section = self.divide_list_by_section(jobs_to_submit) packages_to_submit = list() if platform.allow_arrays: - packages_to_submit.append(JobPackageArray(jobs_to_submit)) + for section_list in jobs_to_submit_by_section.values(): + packages_to_submit.append(JobPackageArray(section_list)) return packages_to_submit for job in jobs_to_submit: packages_to_submit.append(JobPackageSimple([job])) return packages_to_submit return list() # no packages to submit + @staticmethod + def divide_list_by_section(jobs_list): + """ + Returns a dict() with as many keys as 'jobs_list' different sections. + The value for each key is a list() with all the jobs with the key section. + + :param jobs_list: list of jobs to be divided + :rtype: dict + """ + by_section = dict() + for job in jobs_list: + if job.section not in by_section: + by_section[job.section] = list() + by_section[job.section].append(job) + return by_section + class DicJobs: """ -- GitLab From 2d338d56f67192e95b9f90d666109ff6013a4017 Mon Sep 17 00:00:00 2001 From: jlope2 Date: Thu, 15 Dec 2016 17:30:24 +0100 Subject: [PATCH 22/25] Some regression tests commands were added --- test/regression/tests_commands.py | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/test/regression/tests_commands.py b/test/regression/tests_commands.py index 36c427be7..cb7044fe7 100644 --- a/test/regression/tests_commands.py +++ b/test/regression/tests_commands.py @@ -6,12 +6,31 @@ def generate_experiment_cmd(hpc, description): def create_experiment_cmd(experiment_id): - return 'autosubmit -lf EVERYTHING -lc EVERYTHING create ' + experiment_id + ' -np' + return 'autosubmit -lf EVERYTHING -lc EVERYTHING create {0} -np'.format(experiment_id) def run_experiment_cmd(experiment_id): - return 'autosubmit -lf EVERYTHING -lc EVERYTHING run ' + experiment_id + return 'autosubmit -lf EVERYTHING -lc EVERYTHING run {0}'.format(experiment_id) +def monitor_experiment_cmd(experiment_id): + return 'autosubmit -lf EVERYTHING -lc EVERYTHING monitor {0}'.format(experiment_id) + + +def refresh_experiment_cmd(experiment_id): + return 'autosubmit -lf EVERYTHING -lc EVERYTHING refresh {0}'.format(experiment_id) + + +def recovery_experiment_cmd(experiment_id): + return 'autosubmit -lf EVERYTHING -lc EVERYTHING recovery {0} -all -s'.format(experiment_id) + + +def check_experiment_cmd(experiment_id): + return 'autosubmit -lf EVERYTHING -lc EVERYTHING check {0}'.format(experiment_id) + + +def stats_experiment_cmd(experiment_id): + return 'autosubmit -lf EVERYTHING -lc EVERYTHING stats {0} --hide'.format(experiment_id) + def create_database_cmd(): return 'autosubmit install' -- GitLab From 0dce9dc3bc177fa34620ad286621d1b51fb58ea9 Mon Sep 17 00:00:00 2001 From: jlope2 Date: Thu, 15 Dec 2016 17:36:01 +0100 Subject: [PATCH 23/25] Some new commands being involved in regression tests --- test/regression/tests_commands.py | 3 ++- test/regression/tests_runner.py | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/test/regression/tests_commands.py b/test/regression/tests_commands.py index cb7044fe7..9d7e05396 100644 --- a/test/regression/tests_commands.py +++ b/test/regression/tests_commands.py @@ -14,7 +14,7 @@ def run_experiment_cmd(experiment_id): def monitor_experiment_cmd(experiment_id): - return 'autosubmit -lf EVERYTHING -lc EVERYTHING monitor {0}'.format(experiment_id) + return 'autosubmit -lf EVERYTHING -lc EVERYTHING monitor {0} --hide'.format(experiment_id) def refresh_experiment_cmd(experiment_id): @@ -32,5 +32,6 @@ def check_experiment_cmd(experiment_id): def stats_experiment_cmd(experiment_id): return 'autosubmit -lf EVERYTHING -lc EVERYTHING stats {0} --hide'.format(experiment_id) + def create_database_cmd(): return 'autosubmit install' diff --git a/test/regression/tests_runner.py b/test/regression/tests_runner.py index 4602192da..acdc3c0ab 100644 --- a/test/regression/tests_runner.py +++ b/test/regression/tests_runner.py @@ -34,10 +34,34 @@ def run_test_case(experiment_id, name, hpc_arch, description, src_path, retrials Log.warning('Error while creating the experiment {0}({1})', name, experiment_id) continue + if not check_cmd(check_experiment_cmd(experiment_id)): + Log.warning('Error while checking the experiment {0}({1})', name, experiment_id) + continue + + if not check_cmd(monitor_experiment_cmd(experiment_id)): + Log.warning('Error while monitoring the experiment {0}({1})', name, experiment_id) + continue + + if not check_cmd(refresh_experiment_cmd(experiment_id)): + Log.warning('Error while refreshing the experiment {0}({1})', name, experiment_id) + continue + if not check_cmd(run_experiment_cmd(experiment_id)): Log.warning('Error while running the experiment {0}({1})', name, experiment_id) continue + if not check_cmd(monitor_experiment_cmd(experiment_id)): + Log.warning('Error while monitoring the experiment {0}({1})', name, experiment_id) + continue + + if not check_cmd(stats_experiment_cmd(experiment_id)): + Log.warning('Error while getting stats of the experiment {0}({1})', name, experiment_id) + continue + + if not check_cmd(recovery_experiment_cmd(experiment_id)): + Log.warning('Error while recovering the experiment {0}({1})', name, experiment_id) + continue + run_ok = True break if run_ok: -- GitLab From 9167574d5d3c55ac7e5b1d066ce02ef8b2dda0d7 Mon Sep 17 00:00:00 2001 From: jlope2 Date: Mon, 19 Dec 2016 10:36:45 +0100 Subject: [PATCH 24/25] Some test commands were improved --- test/regression/tests_commands.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/regression/tests_commands.py b/test/regression/tests_commands.py index 9d7e05396..e79611d54 100644 --- a/test/regression/tests_commands.py +++ b/test/regression/tests_commands.py @@ -6,7 +6,7 @@ def generate_experiment_cmd(hpc, description): def create_experiment_cmd(experiment_id): - return 'autosubmit -lf EVERYTHING -lc EVERYTHING create {0} -np'.format(experiment_id) + return 'autosubmit -lf EVERYTHING -lc EVERYTHING create {0} --hide'.format(experiment_id) def run_experiment_cmd(experiment_id): @@ -22,7 +22,7 @@ def refresh_experiment_cmd(experiment_id): def recovery_experiment_cmd(experiment_id): - return 'autosubmit -lf EVERYTHING -lc EVERYTHING recovery {0} -all -s'.format(experiment_id) + return 'autosubmit -lf EVERYTHING -lc EVERYTHING recovery {0} -all --hide -s'.format(experiment_id) def check_experiment_cmd(experiment_id): -- GitLab From 5ecb9af346272e6e9d9c0e239265ea4e1e7fb96e Mon Sep 17 00:00:00 2001 From: jlope2 Date: Mon, 19 Dec 2016 10:46:13 +0100 Subject: [PATCH 25/25] Version number bumped to 3.8.0 --- CHANGELOG | 3 +++ VERSION | 2 +- docs/source/conf.py | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 1d24e8584..39830fa43 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +3.8.0 + First version with LSF arrays + 3.7.6 Fixed refresh Fixed recovery for ECMWF diff --git a/VERSION b/VERSION index 897e56be0..19811903a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.7.6 +3.8.0 diff --git a/docs/source/conf.py b/docs/source/conf.py index 99b48afd8..4d08fc1e4 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -62,9 +62,9 @@ author = u'Earth Science Department, Barcelona Supercomputing Center, BSC' # built documents. # # The short X.Y version. -version = '3.7' +version = '3.8' # The full version, including alpha/beta/rc tags. -release = '3.7.6' +release = '3.8.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. -- GitLab