diff --git a/Tools/ART/python/ART/art_base.py b/Tools/ART/python/ART/art_base.py index 9e5db0d990253f0c12878fe352094c6e42a780e7..c9032de7cb6e744b42b8688111c4024d781d69c2 100755 --- a/Tools/ART/python/ART/art_base.py +++ b/Tools/ART/python/ART/art_base.py @@ -10,26 +10,26 @@ import os import sys import yaml -from art_misc import run_command +from art_misc import is_exe, run_command from art_header import ArtHeader class ArtBase(object): """TBD.""" - def __init__(self): + def __init__(self, art_directory): """TBD.""" - pass + self.art_directory = art_directory - def task_list(self, type, sequence_tag): + def task_list(self, job_type, sequence_tag): """TBD.""" self.not_implemented() - def task(self, package, type, sequence_tag): + def task(self, package, job_type, sequence_tag): """TBD.""" self.not_implemented() - def job(self, package, type, sequence_tag, index, out): + def job(self, package, job_type, sequence_tag, index, out): """TBD.""" self.not_implemented() @@ -37,7 +37,7 @@ class ArtBase(object): """TBD.""" self.not_implemented() - def list(self, package, type, json_format=False): + def list(self, package, job_type, json_format=False): """TBD.""" self.not_implemented() @@ -55,9 +55,28 @@ class ArtBase(object): for directory in directories.itervalues(): files = self.get_files(directory) for fname in files: - ArtHeader(os.path.join(directory, fname)).validate() + test_name = os.path.join(directory, fname) + print test_name + if not is_exe(test_name): + print "ERROR: ", test_name, "is not executable." + ArtHeader(test_name).validate() return 0 + def included(self, script_directory, job_type, index_type, nightly_release, project, platform): + """TBD.""" + directories = self.get_test_directories(script_directory.rstrip("/")) + for directory in directories.itervalues(): + files = self.get_files(directory, job_type, index_type) + for fname in files: + test_name = os.path.join(directory, fname) + if self.is_included(test_name, nightly_release, project, platform): + print test_name, ArtHeader(test_name).get('art-include') + return 0 + + def download(self, input_file): + """TBD.""" + return self.get_input(input_file) + # # Default implementations # @@ -92,24 +111,49 @@ class ArtBase(object): config_file.close() return config - def get_files(self, directory, type=None): + def get_files(self, directory, job_type=None, index_type="all", nightly_release=None, project=None, platform=None): """ - Return a list of all test files matching 'test_*.sh' of given 'type'. + Return a list of all test files matching 'test_*.sh' of given 'job_type', 'index_type' and nightly/project/platform. + + 'index_type' can be 'all', 'batch' or 'single'. - If type is None, all files are returned. Only the filenames are returned. + If "given" is None, all files are returned. + + Only the filenames are returned. """ result = [] if directory is not None: files = os.listdir(directory) files.sort() for fname in files: - if fnmatch.fnmatch(fname, 'test_*.sh') or fnmatch.fnmatch(fname, 'test_*.py'): - if type is None or ArtHeader(os.path.join(directory, fname)).get('art-type') == type: - result.append(fname) + # is not a test ? + if not fnmatch.fnmatch(fname, 'test_*.sh') and not fnmatch.fnmatch(fname, 'test_*.py'): + continue + + test_name = os.path.join(directory, fname) + + # is not of correct type + if job_type is not None and ArtHeader(test_name).get('art-type') != job_type: + continue + + # is not included in nightly_release, project, platform + if nightly_release is not None and not self.is_included(test_name, nightly_release, project, platform): + continue + + # batch and does specify art-input + if index_type == "batch" and ArtHeader(test_name).get('art-input') is not None: + continue + + # single and does not specify art-input + if index_type == "single" and ArtHeader(test_name).get('art-input') is None: + continue + + result.append(fname) + return result def get_type(self, directory, test_name): - """Return the 'type' of a test.""" + """Return the 'job_type' of a test.""" return ArtHeader(os.path.join(directory, test_name)).get('art-type') def get_test_directories(self, directory): @@ -125,11 +169,46 @@ class ArtBase(object): result[package] = root return result - def get_list(self, directory, package, type): + def get_list(self, directory, package, job_type, index_type): """Return a list of tests for a particular package.""" test_directories = self.get_test_directories(directory) test_dir = test_directories[package] - return self.get_files(test_dir, type) + return self.get_files(test_dir, job_type, index_type) + + def is_included(self, test_name, nightly_release, project, platform): + """Return true if a match is found for test_name in nightly_release, project, platform.""" + patterns = ArtHeader(test_name).get('art-include') + + for pattern in patterns: + nightly_release_pattern = "*" + project_pattern = "*" + platform_pattern = "*-*-*-opt" + + count = pattern.count('/') + if count >= 2: + (nightly_release_pattern, project_pattern, platform_pattern) = pattern.split('/', 3) + elif count == 1: + (nightly_release_pattern, project_pattern) = pattern.split('/', 2) + else: + nightly_release_pattern = pattern + + if fnmatch.fnmatch(nightly_release, nightly_release_pattern) and fnmatch.fnmatch(project, project_pattern) and fnmatch.fnmatch(platform, platform_pattern): + return True + return False + + def get_input(self, input_name): + """Download input file from rucio. Retuns path of inputfile.""" + work_dir = '.' + + # run in correct environment + env = os.environ.copy() + env['PATH'] = '.:' + env['PATH'] + + (code, out, err) = run_command(os.path.join(self.art_directory, "art-get-input.sh") + " " + input_name, dir=work_dir, env=env) + if code == 0 and out != '': + return os.path.join(work_dir, input_name.replace(':', '/', 1)) + + return None # # Private Methods diff --git a/Tools/ART/python/ART/art_build.py b/Tools/ART/python/ART/art_build.py index 39fd869de8eb55332b171fdb7f2e6a200cc6750d..3c62cb3b11b5396ea66bea42f6b105dd9f4c13e0 100644 --- a/Tools/ART/python/ART/art_build.py +++ b/Tools/ART/python/ART/art_build.py @@ -5,10 +5,11 @@ __author__ = "Tulay Cuhadar Donszelmann <tcuhadar@cern.ch>" import collections +import fnmatch import json import multiprocessing -import re import os +import re from art_misc import run_command, mkdir_p from art_base import ArtBase @@ -17,11 +18,12 @@ from art_header import ArtHeader from parallelScheduler import ParallelScheduler -def run_job(art_directory, sequence_tag, script_directory, package, type, index, test_name, nightly_release, project, platform, nightly_tag): +def run_job(art_directory, sequence_tag, script_directory, package, job_type, index, test_name, nightly_release, project, platform, nightly_tag): """TBD.""" - print "job started", art_directory, sequence_tag, script_directory, package, type, index, test_name, nightly_release, project, platform, nightly_tag - (exit_code, out, err) = run_command(os.path.join(art_directory, './art-internal.py') + " job build " + script_directory + " " + package + " " + type + " " + sequence_tag + " " + str(index) + " " + "out" + " " + nightly_release + " " + project + " " + platform + " " + nightly_tag) - print "job ended", art_directory, sequence_tag, script_directory, package, type, index, test_name, nightly_release, project, platform, nightly_tag + print "job started", art_directory, sequence_tag, script_directory, package, job_type, index, test_name, nightly_release, project, platform, nightly_tag + (exit_code, out, err) = run_command(' '.join((os.path.join(art_directory, './art-internal.py'), "job", "build", script_directory, package, job_type, sequence_tag, str(index), "out", nightly_release, project, platform, nightly_tag))) + print "job ended", art_directory, sequence_tag, script_directory, package, job_type, index, test_name, nightly_release, project, platform, nightly_tag + return (test_name, exit_code, out, err) @@ -30,6 +32,7 @@ class ArtBuild(ArtBase): def __init__(self, art_directory, nightly_release, project, platform, nightly_tag, script_directory, max_jobs=0, ci=False): """TBD.""" + super(ArtBuild, self).__init__(art_directory) # print "ArtBuild", art_directory, script_directory, max_jobs self.art_directory = art_directory self.script_directory = script_directory.rstrip("/") @@ -40,9 +43,9 @@ class ArtBuild(ArtBase): self.max_jobs = multiprocessing.cpu_count() if max_jobs <= 0 else max_jobs self.ci = ci - def task_list(self, type, sequence_tag): + def task_list(self, job_type, sequence_tag): """TBD.""" - # print "task_list", type, sequence_tag + # print "task_list", job_type, sequence_tag test_directories = self.get_test_directories(self.script_directory) if not test_directories: print 'WARNING: No tests found in directories ending in "test"' @@ -50,11 +53,25 @@ class ArtBuild(ArtBase): status = collections.defaultdict(lambda: collections.defaultdict(lambda: collections.defaultdict())) for package, root in test_directories.items(): - job_results = self.task(package, type, sequence_tag) + test_directory = os.path.abspath(test_directories[package]) + job_results = self.task(package, job_type, sequence_tag) for job_result in job_results: - status[package][job_result[0]]['exit_code'] = job_result[1] - status[package][job_result[0]]['out'] = job_result[2] - status[package][job_result[0]]['err'] = job_result[3] + test_name = job_result[0] + status[package][test_name]['exit_code'] = job_result[1] + status[package][test_name]['out'] = job_result[2] + status[package][test_name]['err'] = job_result[3] + status[package][test_name]['test_directory'] = test_directory + + # gather results + result = [] + with open(os.path.join(sequence_tag, package, os.path.splitext(test_name)[0], 'stdout.txt'), 'r') as f: + for line in f: + match = re.search(r"art-result: (.*)", line) + if match: + result = json.loads(match.group(1)) + break + + status[package][job_result[0]]['result'] = result mkdir_p(sequence_tag) with open(os.path.join(sequence_tag, "status.json"), 'w') as outfile: @@ -62,10 +79,10 @@ class ArtBuild(ArtBase): return 0 - def task(self, package, type, sequence_tag): + def task(self, package, job_type, sequence_tag): """TBD.""" - # print "task", package, type, sequence_tag - test_names = self.get_list(self.script_directory, package, type) + # print "task", package, job_type, sequence_tag + test_names = self.get_list(self.script_directory, package, job_type, "all") scheduler = ParallelScheduler(self.max_jobs + 1) index = 0 @@ -76,7 +93,7 @@ class ArtBuild(ArtBase): branch_name = os.environ['AtlasBuildBranch'] cis = ArtHeader(fname).get('art-ci') for ci in cis: - if re.match(ci, branch_name): + if fnmatch.fnmatch(branch_name, ci): schedule_test = True break else: @@ -87,22 +104,23 @@ class ArtBuild(ArtBase): print "job skipped, file not executable: ", fname if schedule_test: - scheduler.add_task(task_name="t" + str(index), dependencies=[], description="d", target_function=run_job, function_kwargs={'art_directory': self.art_directory, 'sequence_tag': sequence_tag, 'script_directory': self.script_directory, 'package': package, 'type': type, 'index': index, 'test_name': test_name, 'nightly_release': self.nightly_release, 'project': self.project, 'platform': self.platform, 'nightly_tag': self.nightly_tag}) + scheduler.add_task(task_name="t" + str(index), dependencies=[], description="d", target_function=run_job, function_kwargs={'art_directory': self.art_directory, 'sequence_tag': sequence_tag, 'script_directory': self.script_directory, 'package': package, 'job_type': job_type, 'index': index, 'test_name': test_name, 'nightly_release': self.nightly_release, 'project': self.project, 'platform': self.platform, 'nightly_tag': self.nightly_tag}) index += 1 - return scheduler.run() + result = scheduler.run() + return result - def job(self, package, type, sequence_tag, index, out): + def job(self, package, job_type, sequence_tag, index, out): """TBD.""" - # print "job", package, type, sequence_tag, index, out + # print "job", package, job_type, sequence_tag, index, out test_directories = self.get_test_directories(self.script_directory) test_directory = os.path.abspath(test_directories[package]) - test_name = self.get_files(test_directory, type)[int(index)] + test_name = self.get_files(test_directory, job_type)[int(index)] work_directory = os.path.join(sequence_tag, package, os.path.splitext(test_name)[0]) mkdir_p(work_directory) - (exit_code, output, err) = run_command(os.path.join(test_directory, test_name) + ' ' + '.' + ' ' + package + ' ' + type + ' ' + test_name + ' ' + self.nightly_release + ' ' + self.project + ' ' + self.platform + ' ' + self.nightly_tag, dir=work_directory) + (exit_code, output, err) = run_command(' '.join((os.path.join(test_directory, test_name), '.', package, job_type, test_name, self.nightly_release, self.project, self.platform, self.nightly_tag)), dir=work_directory) with open(os.path.join(work_directory, "stdout.txt"), "w") as text_file: text_file.write(output) diff --git a/Tools/ART/python/ART/art_grid.py b/Tools/ART/python/ART/art_grid.py index 4edb12a9ca7a37b0f0ae6ef0f59c7a4bc25e3c6b..35e032d525890ffacc3bfe4f2d15fbed8ff5ec16 100644 --- a/Tools/ART/python/ART/art_grid.py +++ b/Tools/ART/python/ART/art_grid.py @@ -18,7 +18,7 @@ import tempfile from art_base import ArtBase from art_header import ArtHeader -from art_misc import mkdir_p, make_executable, check, run_command +from art_misc import mkdir_p, make_executable, run_command, exit_on_failure class ArtGrid(ArtBase): @@ -26,7 +26,7 @@ class ArtGrid(ArtBase): def __init__(self, art_directory, nightly_release, project, platform, nightly_tag, script_directory=None, skip_setup=False, submit_directory=None): """TBD.""" - self.art_directory = art_directory + super(ArtGrid, self).__init__(art_directory) self.nightly_release = nightly_release self.project = project self.platform = platform @@ -50,7 +50,7 @@ class ArtGrid(ArtBase): """Return true if the script directory is in cvmfs.""" return self.get_script_directory().startswith(self.cvmfs_directory) - def task_list(self, type, sequence_tag): + def task_list(self, job_type, sequence_tag): """TBD.""" # job will be submitted from tmp directory submit_directory = tempfile.mkdtemp(dir='.') @@ -58,11 +58,9 @@ class ArtGrid(ArtBase): # make sure tmp is removed afterwards atexit.register(shutil.rmtree, submit_directory) - config = None if self.skip_setup else self.get_config() - # make sure script directory exist if not os.path.isdir(self.get_script_directory()): - print 'ERROR: script directory does not exist: %s' % self.get_script_directory() + print 'ERROR: script directory does not exist:', self.get_script_directory() print 'art-status: error' sys.stdout.flush() exit(1) @@ -74,124 +72,192 @@ class ArtGrid(ArtBase): sys.stdout.flush() for package, root in test_directories.items(): - if self.excluded(config, package): - print 'Excluding ' + package + ' for ' + self.nightly_release + ' project ' + self.project + ' on ' + self.platform + if package in ['TrigInDetValidation']: + continue + + number_of_tests = len(self.get_files(root, job_type, "all", self.nightly_release, self.project, self.platform)) + if number_of_tests > 0: print 'art-package: ' + package - print 'art-status: excluded' + print 'art-status: included' + print 'root' + root + print 'Handling', package, 'for', self.nightly_release, 'project', self.project, 'on', self.platform + print "Number of tests:", str(number_of_tests) + sys.stdout.flush() + submit_dir = os.path.join(submit_directory, package) + run = os.path.join(submit_dir, "run") + ART = os.path.join(run, "ART") + mkdir_p(ART) + + # get the path of the python classes and support scripts + art_python_directory = os.path.join(self.art_directory, '..', 'python', 'ART') + + shutil.copy(os.path.join(self.art_directory, 'art.py'), run) + shutil.copy(os.path.join(self.art_directory, 'art-get-input.sh'), run) + shutil.copy(os.path.join(self.art_directory, 'art-get-tar.sh'), run) + shutil.copy(os.path.join(self.art_directory, 'art-internal.py'), run) + shutil.copy(os.path.join(art_python_directory, '__init__.py'), ART) + shutil.copy(os.path.join(art_python_directory, 'art_base.py'), ART) + shutil.copy(os.path.join(art_python_directory, 'art_build.py'), ART) + shutil.copy(os.path.join(art_python_directory, 'art_grid.py'), ART) + shutil.copy(os.path.join(art_python_directory, 'art_header.py'), ART) + shutil.copy(os.path.join(art_python_directory, 'art_misc.py'), ART) + shutil.copy(os.path.join(art_python_directory, 'docopt.py'), ART) + shutil.copy(os.path.join(art_python_directory, 'docopt_dispatch.py'), ART) + shutil.copy(os.path.join(art_python_directory, 'parallelScheduler.py'), ART) + shutil.copy(os.path.join(art_python_directory, 'serialScheduler.py'), ART) + + make_executable(os.path.join(run, 'art.py')) + make_executable(os.path.join(run, 'art-get-input.sh')) + make_executable(os.path.join(run, 'art-get-tar.sh')) + make_executable(os.path.join(run, 'art-internal.py')) + + # copy a local test directory if needed (only for 'art grid') + if not self.is_script_directory_in_cvmfs(): + local_test_dir = os.path.join(run, os.path.basename(os.path.normpath(self.get_script_directory()))) + print "Copying script directory for grid submission to ", local_test_dir + shutil.copytree(self.get_script_directory(), local_test_dir) + + command = ' '.join((os.path.join(self.art_directory, 'art-internal.py'), 'task', 'grid', '--skip-setup' if self.skip_setup else '', submit_directory, self.get_script_directory(), package, job_type, sequence_tag, self.nightly_release, self.project, self.platform, self.nightly_tag)) + print command + sys.stdout.flush() + + env = os.environ.copy() + env['PATH'] = '.:' + env['PATH'] + out = exit_on_failure(run_command(command, env=env)) + print out sys.stdout.flush() - else: - shell_files = self.get_files(root, type) - number_of_tests = len(shell_files) - if number_of_tests > 0: - print 'art-package: ' + package - print 'art-status: included' - print 'root' + root - print 'Handling ' + package + ' for ' + self.nightly_release + ' project ' + self.project + ' on ' + self.platform - print "Number of tests: " + str(number_of_tests) - sys.stdout.flush() - submit_dir = os.path.join(submit_directory, package) - run = os.path.join(submit_dir, "run") - ART = os.path.join(run, "ART") - mkdir_p(ART) - - # get the path of the python classes and support scripts - art_python_directory = os.path.join(self.art_directory, '..', 'python', 'ART') - - shutil.copy(os.path.join(self.art_directory, 'art.py'), run) - shutil.copy(os.path.join(self.art_directory, 'art-get-tar.sh'), run) - shutil.copy(os.path.join(self.art_directory, 'art-internal.py'), run) - shutil.copy(os.path.join(art_python_directory, '__init__.py'), ART) - shutil.copy(os.path.join(art_python_directory, 'art_base.py'), ART) - shutil.copy(os.path.join(art_python_directory, 'art_build.py'), ART) - shutil.copy(os.path.join(art_python_directory, 'art_grid.py'), ART) - shutil.copy(os.path.join(art_python_directory, 'art_header.py'), ART) - shutil.copy(os.path.join(art_python_directory, 'art_misc.py'), ART) - shutil.copy(os.path.join(art_python_directory, 'docopt.py'), ART) - shutil.copy(os.path.join(art_python_directory, 'docopt_dispatch.py'), ART) - shutil.copy(os.path.join(art_python_directory, 'parallelScheduler.py'), ART) - shutil.copy(os.path.join(art_python_directory, 'serialScheduler.py'), ART) - - make_executable(os.path.join(run, 'art.py')) - make_executable(os.path.join(run, 'art-get-tar.sh')) - make_executable(os.path.join(run, 'art-internal.py')) - - # copy a local test directory if needed (only for 'art grid') - if not self.is_script_directory_in_cvmfs(): - local_test_dir = os.path.join(run, os.path.basename(os.path.normpath(self.get_script_directory()))) - print "Copying script directory for grid submission to ", local_test_dir - shutil.copytree(self.get_script_directory(), local_test_dir) - - command = os.path.join(self.art_directory, 'art-internal.py') + ' task grid ' + ('--skip-setup' if self.skip_setup else '') + ' ' + submit_directory + ' ' + self.get_script_directory() + ' ' + package + ' ' + type + ' ' + sequence_tag + ' ' + self.nightly_release + ' ' + self.project + ' ' + self.platform + ' ' + self.nightly_tag - print command - sys.stdout.flush() - - env = os.environ.copy() - env['PATH'] = '.:' + env['PATH'] - out = check(run_command(command, env=env)) - print out - sys.stdout.flush() return 0 - def task(self, package, type, sequence_tag): + def task(self, package, job_type, sequence_tag): """TBD.""" print 'Running art task' sys.stdout.flush() - number_of_tests = len(self.get_list(self.get_script_directory(), package, type)) - config = None if self.skip_setup else self.get_config() grid_options = self.grid_option(config, package, 'grid-exclude-sites', '--excludedSite=') grid_options += ' ' + self.grid_option(config, package, 'grid-sites', '--site=') - print self.nightly_release + " " + self.project + " " + self.platform + " " + self.nightly_tag + " " + sequence_tag + " " + package + " " + type + " " + str(number_of_tests) + " " + grid_options - sys.stdout.flush() - # run task from Bash Script as is needed in ATLAS setup # FIXME we need to parse the output env = os.environ.copy() env['PATH'] = '.:' + env['PATH'] env['ART_GRID_OPTIONS'] = grid_options - out = check(run_command(os.path.join(self.art_directory, 'art-task-grid.sh') + " " + ('--skip-setup' if self.skip_setup else '') + " " + self.submit_directory + " " + self.get_script_directory() + " " + package + " " + type + " " + sequence_tag + " " + str(number_of_tests) + " " + self.nightly_release + " " + self.project + " " + self.platform + " " + self.nightly_tag, env=env)) - print out - sys.stdout.flush() + + test_directories = self.get_test_directories(self.get_script_directory()) + test_directory = test_directories[package] + number_of_batch_tests = len(self.get_files(test_directory, job_type, "batch", self.nightly_release, self.project, self.platform)) + + MAX_OUTFILE_LEN = 132 + user = env['USER'] if self.skip_setup else 'artprod' + nightly_release_short = re.sub(r"-VAL-.*", "-VAL", self.nightly_release) + outfile = '.'.join(('user', user, 'atlas', nightly_release_short, self.project, self.platform, self.nightly_tag, sequence_tag, package)) + + # submit batch tests + if number_of_batch_tests > 0: + if len(outfile) > MAX_OUTFILE_LEN: + print "ERROR: OutFile string length >", MAX_OUTFILE_LEN, ": ", outfile + sys.stdout.flush() + return 1 + + print "batch:", nightly_release_short, self.project, self.platform, self.nightly_tag, sequence_tag, package, job_type, str(number_of_batch_tests), grid_options + sys.stdout.flush() + + out = exit_on_failure(run_command(' '.join((os.path.join(self.art_directory, 'art-task-grid.sh'), '--skip-setup' if self.skip_setup else '', self.submit_directory, self.get_script_directory(), package, job_type, sequence_tag, str(number_of_batch_tests), nightly_release_short, self.project, self.platform, self.nightly_tag, outfile)), env=env)) + print out + sys.stdout.flush() + + # submit single tests + index = 1 + for test_name in self.get_files(test_directory, job_type, "single", self.nightly_release, self.project, self.platform): + job = os.path.join(test_directory, test_name) + header = ArtHeader(job) + inds = header.get('art-input') + nFiles = header.get('art-input-nfiles') + nEvents = header.get('art-input-nevents') + files = ','.join(header.get('art-input-file')) + split = header.get('art-input-split') + + outfile_test = '.'.join((outfile, str(index))) + if len(outfile_test) > MAX_OUTFILE_LEN: + print "ERROR: OutFile string length >", MAX_OUTFILE_LEN, ": ", outfile_test + sys.stdout.flush() + return 1 + + print "single:", nightly_release_short, self.project, self.platform, self.nightly_tag, sequence_tag, package, job_type, str(split), inds, str(nFiles), str(nEvents), grid_options + sys.stdout.flush() + + out = exit_on_failure(run_command(' '.join((os.path.join(self.art_directory, 'art-task-grid.sh'), '--skip-setup' if self.skip_setup else '', '--test-name ' + test_name, '--inDS ' + inds, '--nFiles ' + str(nFiles) if nFiles > 0 else '', '--nEvents ' + str(nEvents) if nEvents > 0 else '', '--fileList ' + files if files != '' else '', self.submit_directory, self.get_script_directory(), package, job_type, sequence_tag, str(split), nightly_release_short, self.project, self.platform, self.nightly_tag, outfile_test)), env=env)) + print out + sys.stdout.flush() + + index += 1 + return 0 - def job(self, package, type, sequence_tag, index, out): + def job(self, package, job_type, sequence_tag, index_type, index_or_name, out): """TBD.""" print 'Running art job grid' sys.stdout.flush() - index = int(index) - - print self.nightly_release + " " + self.project + " " + self.platform + " " + self.nightly_tag + " " + package + " " + type + " " + str(index) + " " + out + print self.nightly_release, self.project, self.platform, self.nightly_tag, package, job_type, str(index_or_name), out sys.stdout.flush() test_directories = self.get_test_directories(self.get_script_directory()) - test_dir = test_directories[package] - test_list = self.get_files(test_dir, type) + test_directory = test_directories[package] + if index_type == "batch": + test_list = self.get_files(test_directory, job_type, "batch", self.nightly_release, self.project, self.platform) + + # minus one for grid + index = int(index_or_name) + test_name = test_list[index - 1] + else: + test_name = index_or_name - # minus one for grid - test_name = test_list[index - 1] - test_file = os.path.join(test_dir, test_name) - com = '%s %s %s %s %s %s %s %s %s' % (test_file, self.get_script_directory(), package, type, test_name, self.nightly_release, self.project, self.platform, self.nightly_tag) + test_file = os.path.join(test_directory, test_name) + command = ' '.join((test_file, self.get_script_directory(), package, job_type, test_name, self.nightly_release, self.project, self.platform, self.nightly_tag)) print test_name - print test_dir - print com + print test_directory + print command sys.stdout.flush() # run the test env = os.environ.copy() env['PATH'] = '.:' + env['PATH'] - print check(run_command(com, env=env)) + (exit_code, output, error) = run_command(command, env=env) + if (exit_code != 0): + print error + print output sys.stdout.flush() + # gather results + result = {} + result['name'] = test_name + result['exit_code'] = exit_code + result['test_directory'] = test_directory + + # find all 'art-result: x' or 'art-result: [x]' and append them to result list + result['result'] = [] + matches = re.findall(r"art-result: (.*)", output) + for match in matches: + item = json.loads(match) + if isinstance(item, list): + result['result'].extend(item) + else: + result['result'].append(item) + + # write out results + with open(os.path.join("art-job.json"), 'w') as jobfile: + json.dump(result, jobfile, sort_keys=True, indent=4, ensure_ascii=False) + # pick up the outputs tar_file = tarfile.open(out, mode='w') # pick up explicitly named output files with open(test_file, "r") as f: for line in f: + # remove comments + line = line.split('#', 1)[0] out_names = re.findall(r"--output[^\s=]*[= ]*(\S*)", line) print out_names for out_name in out_names: @@ -203,15 +269,16 @@ class ArtGrid(ArtBase): # pick up art-header named outputs for path_name in ArtHeader(test_file).get('art-output'): for out_name in glob.glob(path_name): - print 'Tar file contain: ', out_name + print 'Tar file contains:', out_name tar_file.add(out_name) tar_file.close() + # Always return 0 return 0 - def list(self, package, type, json_format=False): + def list(self, package, job_type, index_type, json_format=False): """TBD.""" - jobs = self.get_list(self.get_script_directory(), package, type) + jobs = self.get_list(self.get_script_directory(), package, job_type, index_type) if json_format: json.dump(jobs, sys.stdout, sort_keys=True, indent=4) return 0 @@ -237,7 +304,7 @@ class ArtGrid(ArtBase): def output(self, package, test_name, file_name): """TBD.""" - tar = self.get_tar(package, test_name, '_EXT0') + tar = self.get_tar(package, test_name, '_EXT1') for member in tar.getmembers(): if file_name in member.name: @@ -258,7 +325,7 @@ class ArtGrid(ArtBase): ref_dir = os.path.join('.', 'ref-' + previous_nightly_tag) mkdir_p(ref_dir) - tar = self.get_tar(package, test_name, '_EXT0', previous_nightly_tag) + tar = self.get_tar(package, test_name, '_EXT1', previous_nightly_tag) if tar is None: print "ERROR: No comparison tar file found" # do not flag as error, to make sure tar file gets uploaded @@ -272,68 +339,31 @@ class ArtGrid(ArtBase): for file_name in file_names: ref_file = os.path.join(ref_dir, file_name) if os.path.isfile(ref_file): - print "art-compare: " + previous_nightly_tag + " " + file_name + print "art-compare:", previous_nightly_tag, file_name self.compare_ref(file_name, ref_file, 10) else: print "ERROR:", ref_file, "not found in tar file" # do not flag as error, to make sure tar file gets uploaded return 0 - # - # Protected Methods - # - def excluded(self, config, package): - """Based on config, decide if a release is excluded from testing.""" - # NOTE changes in here should be reflected in art-submit/art-gitlab.py - if config is None: - return False - - if self.nightly_release not in config['releases'].keys(): - return True - - if self.project not in config['releases'][self.nightly_release].keys(): - return True - - if self.platform not in config['releases'][self.nightly_release][self.project].keys(): - return True - - # no packages listed -> included - if config['releases'][self.nightly_release][self.project][self.platform] is None: - return False - - # package not listed -> included - if package not in config['releases'][self.nightly_release][self.project][self.platform].keys(): - return False - - return config['releases'][self.nightly_release][self.project][self.platform][package].get('excluded', False) - def grid_option(self, config, package, key, option_key): - """Based on config, return value for key, or ''.""" - if config is None: - return '' - - if self.nightly_release not in config['releases'].keys(): - return '' - - if self.project not in config['releases'][self.nightly_release].keys(): - return '' + """Based on config, return value for key, or ''. - if self.platform not in config['releases'][self.nightly_release][self.project].keys(): - return '' - - if config['releases'][self.nightly_release][self.project][self.platform] is None: + A global value is pre-pended if found. If not local value is found only the global value is returned, or ''. + """ + if config is None: return '' - prefix = config.get(key, None) - if package not in config['releases'][self.nightly_release][self.project][self.platform].keys(): - return '' if prefix is None else option_key + prefix + global_value = config.get(key) + if package not in config.keys(): + return '' if global_value is None else option_key + global_value - value = config['releases'][self.nightly_release][self.project][self.platform][package].get(key, None) + value = config.get(package).get(key) - if prefix is None: + if global_value is None: return '' if value is None else option_key + value else: - return option_key + prefix + ('' if value is None else ', ' + value) + return option_key + global_value + ('' if value is None else ', ' + value) def get_tar(self, package, test_name, extension, nightly_tag=None): """Open tar file for particular release.""" @@ -341,9 +371,9 @@ class ArtGrid(ArtBase): nightly_tag = self.nightly_tag try: - type = self.get_type(self.get_test_directories(self.get_script_directory())[package], test_name) - print "Type:", type - files = self.get_list(self.get_script_directory(), package, type) + job_type = self.get_type(self.get_test_directories(self.get_script_directory())[package], test_name) + print "Job Type:", job_type + files = self.get_list(self.get_script_directory(), package, job_type, "batch") number_of_tests = len(files) index = files.index(test_name) print "Index:", index @@ -371,7 +401,7 @@ class ArtGrid(ArtBase): try_index = (retry * number_of_tests) + index print (retry + 1), ": Get tar for index ", try_index # run art-get-tar.sh - (code, out, err) = run_command(os.path.join(self.art_directory, "art-get-tar.sh") + " " + package + " " + str(try_index) + " _EXT0 " + self.nightly_release + " " + self.project + " " + self.platform + " " + nightly_tag, dir=tmpdir, env=env) + (code, out, err) = run_command(' '.join((os.path.join(self.art_directory, "art-get-tar.sh"), package, str(try_index), "_EXT1", self.nightly_release, self.project, self.platform, nightly_tag)), dir=tmpdir, env=env) if code == 0 and out != '': match = re.search(r"TAR_NAME=(.*)", out) @@ -386,9 +416,9 @@ class ArtGrid(ArtBase): retry += 1 if retry >= retries: - print "Code: " + str(code) - print "Err: " + err - print "Out: " + out + print "Code:", str(code) + print "Err:", err + print "Out:", out return None return tarfile.open(os.path.join(tmpdir, tar_name.replace(':', '/', 1))) diff --git a/Tools/ART/python/ART/art_header.py b/Tools/ART/python/ART/art_header.py index 6bfecfeea510e6b01a23ba75670f200212a72874..046de1b53d7ae113a96cd6ffd266501063149acd 100644 --- a/Tools/ART/python/ART/art_header.py +++ b/Tools/ART/python/ART/art_header.py @@ -6,7 +6,7 @@ __author__ = "Tulay Cuhadar Donszelmann <tcuhadar@cern.ch>" import re -from copy import copy +from types import IntType from types import ListType from types import StringType @@ -16,59 +16,78 @@ class ArtHeader(object): def __init__(self, filename): """TBD.""" - self.header = re.compile(r'#\s(art-[\w-]+):\s+(.+)$') + self.header_format = re.compile(r'#\s(art-[\w-]+):\s+(.+)$') self.header_format_error1 = re.compile(r'#(art-[\w-]+):\s*(.+)$') self.header_format_error2 = re.compile(r'#\s\s+(art-[\w-]+):\s*(.+)$') self.header_format_error3 = re.compile(r'#\s(art-[\w-]+):\S(.*)$') self.filename = filename - self.type = {} - self.defaultValue = {} - self.constraint = {} - self.value = {} + self.header = {} + # general self.add('art-description', StringType, '') self.add('art-type', StringType, None, ['build', 'grid']) + + # "build" type only self.add('art-ci', ListType, []) + + # "grid" type only + self.add('art-include', ListType, ['*']) self.add('art-output', ListType, []) + self.add('art-input', StringType, None) + self.add('art-input-file', ListType, []) + self.add('art-input-nfiles', IntType, 0) + self.add('art-input-nevents', IntType, 0) + self.add('art-input-split', IntType, 0) self.read(filename) - def add(self, key, type, defaultValue=None, constraint=None): + def add(self, key, value_type, default_value=None, constraint=None): """TBD.""" - self.type[key] = type - self.defaultValue[key] = defaultValue - self.constraint[key] = constraint - self.value[key] = copy(defaultValue) + self.header[key] = {} + self.header[key]['type'] = value_type + self.header[key]['default'] = default_value + self.header[key]['constraint'] = constraint + self.header[key]['value'] = None # never set def is_list(self, key): """TBD.""" - return self.type[key] is ListType if key in self.type else False + return self.header[key]['type'] is ListType if key in self.header else False def read(self, filename): """Read all headers from file.""" for line in open(filename, "r"): - line_match = self.header.match(line) + line_match = self.header_format.match(line) if line_match: key = line_match.group(1) value = line_match.group(2) - if self.type[key] == StringType: + if key in self.header and self.header[key]['type'] == StringType: value = value.strip() if self.is_list(key): - self.value[key].append(value) + if self.header[key]['value'] is None: + self.header[key]['value'] = [] + self.header[key]['value'].append(value) else: - self.value[key] = value + if key not in self.header: + self.header[key] = {} + self.header[key]['value'] = value def get(self, key): """TBD.""" - return self.value[key] if key in self.value else None + if key not in self.header: + return None + + if self.header[key]['value'] is None: + return self.header[key]['default'] + + return self.header[key]['value'] def print_it(self): """TBD.""" - for key in self.type: - print key, self.type[key], self.defaultValue[key], self.value[key], self.constraint[key] + for key in self.header: + print key, self.header[key]['type'], self.header[key]['default'], self.header[key]['value'], self.header[key]['constraint'] def validate(self): """ @@ -78,7 +97,7 @@ class ArtHeader(object): - a header is spaced correctly (e.g. '#art-header: value') - a value in a header is not spaced correctly (e.g. '# art-header:value') - a key is found which is not defined - - a value is found of the wrong type + - a value is found of the wrong value_type - a value is found outside the constraint """ for line in open(self.filename, "r"): @@ -95,20 +114,20 @@ class ArtHeader(object): print "ERROR: Header Validation - invalid header format, use at least one space between ': and value' in file", self.filename print - for key in self.value: - if key not in self.type: - print "ERROR: Header Validation - Invalid key: '" + key + "' in file", self.filename + for key in self.header: + if 'type' not in self.header[key]: + print "ERROR: Header Validation - Invalid key:", key, "in file", self.filename print continue - if type(self.value[key]) != self.type[key]: - if not isinstance(self.value[key], type(None)): - print "ERROR: Header Validation - type:", type(self.value[key]), "not valid for key:", key, "expected type:", self.type[key], "in file", self.filename + if type(self.header[key]['value']) != self.header[key]['type']: + if not isinstance(self.header[key]['value'], type(None)): + print "ERROR: Header Validation - value_type:", type(self.header[key]['value']), "not valid for key:", key, "expected value_type:", self.header[key]['type'], "in file", self.filename print - if self.constraint[key] is not None and self.value[key] not in self.constraint[key]: - if self.value[key] is None: - print "ERROR: Header Validation - missing key: '" + key + "' in file", self.filename + if self.header[key]['constraint'] is not None and self.header[key]['value'] not in self.header[key]['constraint']: + if self.header[key]['value'] is None: + print "ERROR: Header Validation - missing key:", key, "in file", self.filename else: - print "ERROR: Header Validation - value: '" + self.value[key] + "' for key: '" + key + "' not in constraints:", self.constraint[key], "in file", self.filename + print "ERROR: Header Validation - value:", self.header[key]['value'], "for key:", key, "not in constraints:", self.header[key]['constraint'], "in file", self.filename print return 0 diff --git a/Tools/ART/python/ART/art_misc.py b/Tools/ART/python/ART/art_misc.py index 3b98072b024f697004b26ce07d025493f82089cc..edb77fe5ebe1783f121b46d7b5a40e240254b2db 100644 --- a/Tools/ART/python/ART/art_misc.py +++ b/Tools/ART/python/ART/art_misc.py @@ -33,39 +33,44 @@ def run_command(cmd, dir=None, shell=False, env=None): return exit_code, str(output), str(err) -def check((exitcode, out, err)): +def exit_on_failure((exit_code, out, err)): """Check exitcode and print statement and exit if needed.""" - if exitcode == 0: + if exit_code == 0: print err return out - print "Error:", exitcode + print "Error:", exit_code print "StdOut:", out print "StdErr:", err print 'art-status: error' - exit(exitcode) + exit(exit_code) -def verify((exitcode, out, err)): +def code_tbr((exit_code, out, err)): """Check exitcode and print statement.""" - if exitcode == 0: + if exit_code == 0: print out - return exitcode + return exit_code - print "Error:", exitcode + print "Error:", exit_code print "StdOut:", out print "StdErr:", err - return exitcode + return exit_code -def redirect((exitcode, out, err)): +def redirect_tbr((exitcode, out, err)): """Check exitcode.""" return exitcode +def is_exe(fpath): + """Return True if fpath is executable.""" + return os.path.isfile(fpath) and os.access(fpath, os.X_OK) + + def make_executable(path): """Make file executable (chmod +x).""" mode = os.stat(path).st_mode diff --git a/Tools/ART/scripts/art-get-input.sh b/Tools/ART/scripts/art-get-input.sh new file mode 100755 index 0000000000000000000000000000000000000000..5a6115e59381066240bf418ee362cfbfb0e6e544 --- /dev/null +++ b/Tools/ART/scripts/art-get-input.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +# +# NOTE do NOT run with /bin/bash -x as the output is too big for gitlab-ci +# arguments: INPUTNAME +# +# author : Tulay Cuhadar Donszelmann <tcuhadar@cern.ch> +# +# example: CONTAINER_ID:ENTRY_NAME + +if [ $# -ne 1 ]; then + echo 'Usage: art-get-input.sh INPUTNAME' + exit 1 +fi + +echo "Script executed by $(whoami) on $(date)" +echo "User: ${USER}" + +INPUTNAME=$1 +shift + +export ATLAS_LOCAL_ROOT_BASE=/cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase +source $ATLAS_LOCAL_ROOT_BASE/user/atlasLocalSetup.sh + +unset ALRB_noGridMW + +lsetup -f rucio + +echo "InputName: ${INPUTNAME}" + +# Do not use: rucio delivers warnings as exit code 127 +#set -e + +rucio download ${INPUTNAME} diff --git a/Tools/ART/scripts/art-get-tar.sh b/Tools/ART/scripts/art-get-tar.sh index e5c1e302a2c852f2b2d58c4f5273371a3f86e754..23de65640703a42cc83f6497ea197d2092071917 100755 --- a/Tools/ART/scripts/art-get-tar.sh +++ b/Tools/ART/scripts/art-get-tar.sh @@ -3,7 +3,6 @@ # # NOTE do NOT run with /bin/bash -x as the output is too big for gitlab-ci # arguments: PACKAGE INDEX EXTENSION NIGHTLY_RELEASE PROJECT PLATFORM NIGHTLY_TAG -# env: ART_GRID_OPTIONS # # author : Tulay Cuhadar Donszelmann <tcuhadar@cern.ch> # diff --git a/Tools/ART/scripts/art-internal.py b/Tools/ART/scripts/art-internal.py index 52984aa30306196fe0b2a7695aacbc4d00d542f2..029ac3b1e559863b12e0ec70079bacf03cdafbfe 100755 --- a/Tools/ART/scripts/art-internal.py +++ b/Tools/ART/scripts/art-internal.py @@ -5,7 +5,7 @@ ART-internal - ATLAS Release Tester (internal command). Usage: art-internal.py job build [-v] <script_directory> <package> <job_type> <sequence_tag> <index> <out> <nightly_release> <project> <platform> <nightly_tag> - art-internal.py job grid [-v --skip-setup] <script_directory> <package> <job_type> <sequence_tag> <index> <out> <nightly_release> <project> <platform> <nightly_tag> + art-internal.py job grid [-v --skip-setup] <script_directory> <package> <job_type> <sequence_tag> <index_type> <index_or_name> <out> <nightly_release> <project> <platform> <nightly_tag> art-internal.py task build [-v] <script_directory> <package> <job_type> <sequence_tag> <nightly_release> <project> <platform> <nightly_tag> art-internal.py task grid [-v --skip-setup] <submit_directory> <script_directory> <package> <job_type> <sequence_tag> <nightly_release> <project> <platform> <nightly_tag> @@ -20,7 +20,9 @@ Sub-commands: task Runs a single task, consisting of given number of jobs Arguments: + index_type Type of index used (e.g. batch or single) index Index of the test inside the package + index_or_name Index of the test (batch), or its name (single) nightly_release Name of the nightly release (e.g. 21.0) nightly_tag Nightly tag (e.g. 2017-02-26T2119) out Tar filename used for the output of the job @@ -55,7 +57,7 @@ def job_build(script_directory, package, job_type, sequence_tag, index, out, nig @dispatch.on('job', 'grid') -def job_grid(script_directory, package, job_type, sequence_tag, index, out, nightly_release, project, platform, nightly_tag, **kwargs): +def job_grid(script_directory, package, job_type, sequence_tag, index_type, index_or_name, out, nightly_release, project, platform, nightly_tag, **kwargs): """TBD. Tests are called with the following parameters: @@ -63,14 +65,14 @@ def job_grid(script_directory, package, job_type, sequence_tag, index, out, nigh """ art_directory = os.path.dirname(os.path.realpath(sys.argv[0])) skip_setup = kwargs['skip_setup'] - exit(ArtGrid(art_directory, nightly_release, project, platform, nightly_tag, script_directory, skip_setup).job(package, job_type, sequence_tag, index, out)) + exit(ArtGrid(art_directory, nightly_release, project, platform, nightly_tag, script_directory, skip_setup).job(package, job_type, sequence_tag, index_type, index_or_name, out)) @dispatch.on('task', 'build') -def task_build(script_directory, job_type, sequence_tag, nightly_release, project, platform, nightly_tag, **kwargs): +def task_build(script_directory, package, job_type, sequence_tag, nightly_release, project, platform, nightly_tag, **kwargs): """TBD.""" art_directory = os.path.dirname(os.path.realpath(sys.argv[0])) - exit(ArtBuild(art_directory, nightly_release, project, platform, nightly_tag, script_directory).task(job_type, sequence_tag)) + exit(ArtBuild(art_directory, nightly_release, project, platform, nightly_tag, script_directory).task(package, job_type, sequence_tag)) @dispatch.on('task', 'grid') diff --git a/Tools/ART/scripts/art-task-grid.sh b/Tools/ART/scripts/art-task-grid.sh index 606056c0df311cdb81e382982e7466e2b7733b43..2c15ff91e7c0452447a7bc604218c9339c2eff00 100755 --- a/Tools/ART/scripts/art-task-grid.sh +++ b/Tools/ART/scripts/art-task-grid.sh @@ -2,12 +2,14 @@ # Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration # # NOTE do NOT run with /bin/bash -x as the output is too big for gitlab-ci -# arguments: [options] SUBMIT_DIRECTORY SCRIPT_DIRECTORY PACKAGE SEQUENCE_TAG NUMBER_OF_TESTS NIGHTLY_RELEASE PROJECT PLATFORM NIGHTLY_TAG +# arguments: [options] SUBMIT_DIRECTORY SCRIPT_DIRECTORY PACKAGE SEQUENCE_TAG SPLIT NIGHTLY_RELEASE_SHORT PROJECT PLATFORM NIGHTLY_TAG OUT_FILE # env: ART_GRID_OPTIONS # # author : Tulay Cuhadar Donszelmann <tcuhadar@cern.ch> # -# example: [--skip-setup] tmp /cvmfs/atlas-nightlies.cern.ch/sw/... Tier0ChainTests grid 316236 32 21.0 Athena x86_64-slc6-gcc62-opt 2017-02-26T2119 +# options have to be in-order +# +# example: [--skip-setup --test-name TestName --inDS user.tcuhadar.SingleMuon... --nFiles 3 --nEventsPerFile 5] tmp /cvmfs/atlas-nightlies.cern.ch/sw/... Tier0ChainTests grid 316236 3 21.0 Athena x86_64-slc6-gcc62-opt 2017-02-26T2119 user.${USER}.atlas.${NIGHTLY_RELEASE_SHORT}.${PROJECT}.${PLATFORM}.${NIGHTLY_TAG}.${SEQUENCE_TAG}.${PACKAGE}[.${TEST_NUMBER}] #set -e echo "Script executed by $(whoami) on $(date)" @@ -17,6 +19,38 @@ if [ $1 == "--skip-setup" ]; then SKIP_SETUP=1 shift fi +TYPE_OPTION="batch %RNDM:0" +PATHENA_OPTIONS="--destSE=CERN-PROD_SCRATCHDISK" +if [ $1 == "--test-name" ]; then + TYPE_OPTION="single $2" + PATHENA_OPTIONS="--destSE=CERN-PROD_SCRATCHDISK --forceStaged" + shift + shift +fi +INDS="" +if [ $1 == "--inDS" ]; then + INDS="--inDS $2" + shift + shift +fi +NFILES="" +if [ $1 == "--nFiles" ]; then + NFILES="--nFiles $2" + shift + shift +fi +NEVENTS="" +if [ $1 == "--nEvents" ]; then + NEVENTS="--nEventsPerFile $2" + shift + shift +fi +FILELIST="" +if [ $1 == "--fileList" ]; then + FILELIST="--fileList $2" + shift + shift +fi SUBMIT_DIRECTORY=$1 shift SCRIPT_DIRECTORY=$1 @@ -27,9 +61,9 @@ TYPE=$1 shift SEQUENCE_TAG=$1 shift -NUMBER_OF_TESTS=$1 +SPLIT=$1 shift -NIGHTLY_RELEASE=$1 +NIGHTLY_RELEASE_SHORT=$1 shift PROJECT=$1 shift @@ -37,13 +71,12 @@ PLATFORM=$1 shift NIGHTLY_TAG=$1 shift +OUTFILE=$1 +shift # we seem to have to copy the env variables locally GRID_OPTIONS=$ART_GRID_OPTIONS -# change -VAL-Prod and others into -VAL -NIGHTLY_RELEASE_SHORT=${NIGHTLY_RELEASE/-VAL-*/-VAL} - if [ ${SKIP_SETUP} -eq 0 ]; then echo "Setting up release: ${PLATFORM} ${NIGHTLY_RELEASE_SHORT} ${NIGHTLY_TAG} ${PROJECT}" USER=artprod @@ -59,14 +92,22 @@ if [ ${SKIP_SETUP} -eq 0 ]; then fi +if [ ${SPLIT} -eq 0 ]; then + SPLIT="" +else + SPLIT="--split ${SPLIT}" +fi + # NOTE: for art-internal.py the current dir can be used as it is copied there cd ${SUBMIT_DIRECTORY}/${PACKAGE}/run -OUTFILE="user.${USER}.atlas.${NIGHTLY_RELEASE_SHORT}.${PROJECT}.${PLATFORM}.${NIGHTLY_TAG}.${SEQUENCE_TAG}.${PACKAGE}" -CMD="pathena ${GRID_OPTIONS} --noBuild --expertOnly_skipScout --trf \"./art-internal.py job grid ${SCRIPT_DIRECTORY} ${PACKAGE} ${TYPE} ${SEQUENCE_TAG} %RNDM:0 %OUT.tar ${NIGHTLY_RELEASE_SHORT} ${PROJECT} ${PLATFORM} ${NIGHTLY_TAG}\" --split ${NUMBER_OF_TESTS} --outDS ${OUTFILE}" +SUBCOMMAND="./art-internal.py job grid ${SCRIPT_DIRECTORY} ${PACKAGE} ${TYPE} ${SEQUENCE_TAG} ${TYPE_OPTION} %OUT.tar ${NIGHTLY_RELEASE_SHORT} ${PROJECT} ${PLATFORM} ${NIGHTLY_TAG}" +CMD="pathena ${GRID_OPTIONS} ${PATHENA_OPTIONS} --noBuild --expertOnly_skipScout --trf \"${SUBCOMMAND}\" ${SPLIT} --outDS ${OUTFILE} --extOutFile art-job.json ${INDS} ${NFILES} ${NEVENTS} ${FILELIST}" + #--disableAutoRetry #--excludedSite=ANALY_TECHNION-HEP-CREAM #--site=ANALY_NIKHEF-ELPROD_SHORT,ANALY_NIKHEF-ELPROD" #--site=ANALY_FZK,ANALY_BNL,ANALY_RAL" + echo ${CMD} RESULT=`eval "${CMD}"` diff --git a/Tools/ART/scripts/art.py b/Tools/ART/scripts/art.py index ac0fc5a1bbeea436a232f46f5999341f063ee786..9a0da14c933f88fded8f57ea55f36d1728e0a2d7 100755 --- a/Tools/ART/scripts/art.py +++ b/Tools/ART/scripts/art.py @@ -4,22 +4,25 @@ ART - ATLAS Release Tester. Usage: - art.py run [-v --type=<T> --max-jobs=<N> --ci] <script_directory> <sequence_tag> - art.py grid [-v --type=<T>] <script_directory> <sequence_tag> - art.py submit [-v --type=<T>] <sequence_tag> <nightly_release> <project> <platform> <nightly_tag> - art.py validate [-v] <script_directory> - art.py compare grid [-v --days=<D>] <nightly_release> <project> <platform> <nightly_tag> <package> <test_name> <file_name>... + art.py run [-v --type=<T> --max-jobs=<N> --ci] <script_directory> <sequence_tag> + art.py grid [-v --type=<T>] <script_directory> <sequence_tag> + art.py submit [-v --type=<T>] <sequence_tag> <nightly_release> <project> <platform> <nightly_tag> + art.py validate [-v] <script_directory> + art.py included [-v --type=<T> --test-type=<TT>] <script_directory> [<nightly_release> <project> <platform>] + art.py compare grid [-v --days=<D>] <nightly_release> <project> <platform> <nightly_tag> <package> <test_name> <file_name>... art.py compare ref [-v] <file_name> <ref_file> - art.py list grid [-v --json --type=<T>] <package> <nightly_release> <project> <platform> <nightly_tag> - art.py log grid [-v] <package> <test_name> <nightly_release> <project> <platform> <nightly_tag> - art.py output grid [-v] <package> <test_name> <file_name> <nightly_release> <project> <platform> <nightly_tag> + art.py download [-v] <input_file> + art.py list grid [-v --json --type=<T> --test-type=<TT>] <package> <nightly_release> <project> <platform> <nightly_tag> + art.py log grid [-v] <package> <test_name> <nightly_release> <project> <platform> <nightly_tag> + art.py output grid [-v] <package> <test_name> <file_name> <nightly_release> <project> <platform> <nightly_tag> Options: --ci Run Continuous Integration tests only (using env: AtlasBuildBranch) --days=<D> Number of days ago to pick up reference for compare [default: 1] --json Output in json format - --max-jobs=<N> Maximum number of concurrent jobs to run + --max-jobs=<N> Maximum number of concurrent jobs to run [default: 0] --type=<T> Type of job (e.g. grid, build) + --test-type=<TT> Type of test (e.g. all, batch or single) -h --help Show this screen. -v, --verbose Show details. --version Show version. @@ -29,7 +32,9 @@ Sub-commands: grid Run jobs from a package on the grid (needs release and grid setup) submit Submit nightly jobs to the grid (NOT for users) validate Check headers in tests + included Shows list of files which will be included for art submit/art grid compare Compare the output of a job + download Download a file from rucio list Lists the jobs of a package log Show the log of a job output Get the output of a job @@ -37,6 +42,7 @@ Sub-commands: Arguments: file_name Filename to save the output to index Index of the test inside the package + input_file Input file to download (e.g. CONTAINER_ID:ENTRY_NAME) nightly_release Name of the nightly release (e.g. 21.0) nightly_tag Nightly tag (e.g. 2017-02-26T2119) out Tar filename used for the output of the job @@ -46,11 +52,10 @@ Arguments: script_directory Directory containing the package(s) with tests sequence_tag Sequence tag (e.g. 0 or PIPELINE_ID) test_name Name of the test inside the package (e.g. test_q322.sh) - job_type Type of job (e.g. grid, build) """ __author__ = "Tulay Cuhadar Donszelmann <tcuhadar@cern.ch>" -__version__ = '0.0.7' +__version__ = '0.5.4' import os import sys @@ -67,7 +72,8 @@ from ART import ArtBase, ArtGrid, ArtBuild @dispatch.on('compare', 'ref') def compare_ref(file_name, ref_file, **kwargs): """TBD.""" - exit(ArtBase().compare_ref(file_name, ref_file)) + art_directory = os.path.dirname(os.path.realpath(sys.argv[0])) + exit(ArtBase(art_directory).compare_ref(file_name, ref_file)) @dispatch.on('compare', 'grid') @@ -82,10 +88,11 @@ def compare_grid(package, test_name, nightly_release, project, platform, nightly @dispatch.on('list', 'grid') def list(package, nightly_release, project, platform, nightly_tag, **kwargs): """TBD.""" - json_format = kwargs['json'] art_directory = os.path.dirname(os.path.realpath(sys.argv[0])) job_type = 'grid' if kwargs['type'] is None else kwargs['type'] - exit(ArtGrid(art_directory, nightly_release, project, platform, nightly_tag).list(package, job_type, json_format)) + index_type = 'all' if kwargs['test_type'] is None else kwargs['test_type'] + json_format = kwargs['json'] + exit(ArtGrid(art_directory, nightly_release, project, platform, nightly_tag).list(package, job_type, index_type, json_format)) @dispatch.on('log', 'grid') @@ -106,8 +113,8 @@ def output(package, test_name, file_name, nightly_release, project, platform, ni def submit(sequence_tag, nightly_release, project, platform, nightly_tag, **kwargs): """TBD.""" art_directory = os.path.dirname(os.path.realpath(sys.argv[0])) - type = 'grid' if kwargs['type'] is None else kwargs['type'] - exit(ArtGrid(art_directory, nightly_release, project, platform, nightly_tag).task_list(type, sequence_tag)) + job_type = 'grid' if kwargs['type'] is None else kwargs['type'] + exit(ArtGrid(art_directory, nightly_release, project, platform, nightly_tag).task_list(job_type, sequence_tag)) @dispatch.on('grid') @@ -122,8 +129,8 @@ def grid(script_directory, sequence_tag, **kwargs): except KeyError, e: print "Environment variable not set", e sys.exit(1) - type = 'grid' if kwargs['type'] is None else kwargs['type'] - exit(ArtGrid(art_directory, nightly_release, project, platform, nightly_tag, script_directory, True).task_list(type, sequence_tag)) + art_type = 'grid' if kwargs['type'] is None else kwargs['type'] + exit(ArtGrid(art_directory, nightly_release, project, platform, nightly_tag, script_directory, True).task_list(art_type, sequence_tag)) @dispatch.on('run') @@ -138,14 +145,34 @@ def run(script_directory, sequence_tag, **kwargs): except KeyError, e: print "Environment variable not set", e sys.exit(1) - type = 'build' if kwargs['type'] is None else kwargs['type'] - exit(ArtBuild(art_directory, nightly_release, project, platform, nightly_tag, script_directory, max_jobs=kwargs['max_jobs'], ci=kwargs['ci']).task_list(type, sequence_tag)) + art_type = 'build' if kwargs['type'] is None else kwargs['type'] + exit(ArtBuild(art_directory, nightly_release, project, platform, nightly_tag, script_directory, max_jobs=int(kwargs['max_jobs']), ci=kwargs['ci']).task_list(art_type, sequence_tag)) @dispatch.on('validate') def validate(script_directory, **kwargs): """TBD.""" - exit(ArtBase().validate(script_directory)) + art_directory = os.path.dirname(os.path.realpath(sys.argv[0])) + exit(ArtBase(art_directory).validate(script_directory)) + + +@dispatch.on('included') +def included(script_directory, **kwargs): + """TBD.""" + art_directory = os.path.dirname(os.path.realpath(sys.argv[0])) + nightly_release = os.environ['AtlasBuildBranch'] if kwargs['nightly_release'] is None else kwargs['nightly_release'] + project = os.environ['AtlasProject'] if kwargs['project'] is None else kwargs['project'] + platform = os.environ[project + '_PLATFORM'] if kwargs['platform'] is None else kwargs['platform'] + art_type = 'grid' if kwargs['type'] is None else kwargs['type'] + index_type = 'all' if kwargs['test_type'] is None else kwargs['test_type'] + exit(ArtBase(art_directory).included(script_directory, art_type, index_type, nightly_release, project, platform)) + + +@dispatch.on('download') +def download(input_file, **kwargs): + """TBD.""" + art_directory = os.path.dirname(os.path.realpath(sys.argv[0])) + exit(ArtBase(art_directory).download(input_file)) if __name__ == '__main__':