1*9c5db199SXin Li#!/usr/bin/python3 2*9c5db199SXin Li""" 3*9c5db199SXin LiThis script will scan an autotest server results directory for job result 4*9c5db199SXin Lidirectories that have completed and that have not yet been published on 5*9c5db199SXin Lia remote dashboard server matching given filtering options and for those it 6*9c5db199SXin Lifinds it will rsync them to the tko server and mark them as published (it uses 7*9c5db199SXin Lia <jobdir>/.tko_published flag file to determine if a jobdir results directory 8*9c5db199SXin Lihas been published yet). 9*9c5db199SXin Li""" 10*9c5db199SXin Li 11*9c5db199SXin Lifrom __future__ import absolute_import 12*9c5db199SXin Lifrom __future__ import division 13*9c5db199SXin Lifrom __future__ import print_function 14*9c5db199SXin Li 15*9c5db199SXin Liimport sys, os, re, optparse 16*9c5db199SXin Li 17*9c5db199SXin Liimport common 18*9c5db199SXin Lifrom autotest_lib.client.common_lib import utils 19*9c5db199SXin Lifrom autotest_lib.server import frontend 20*9c5db199SXin Li 21*9c5db199SXin Lioptions = optparse.Values() 22*9c5db199SXin Li 23*9c5db199SXin LiUSAGE="""tko-publish [options] <resultsdir> <rsync-destination-path> 24*9c5db199SXin Li 25*9c5db199SXin LiWhere: 26*9c5db199SXin Li<resultsdir> A path to the directory having the job results 27*9c5db199SXin Li directories to publish. 28*9c5db199SXin Li 29*9c5db199SXin Li<rsync-destination-path> A valid rsync destination path where to upload the 30*9c5db199SXin Li job result directories. 31*9c5db199SXin Li Example: [email protected]:/home/autotest/results""" 32*9c5db199SXin LiPUBLISH_FLAGFILE = '.tko_published' 33*9c5db199SXin LiRSYNC_COMMAND = 'rsync -aqz "%s" "%s"' 34*9c5db199SXin Li 35*9c5db199SXin Li 36*9c5db199SXin Lidef get_job_dirs(path): 37*9c5db199SXin Li regex = re.compile('[1-9][0-9]*-') 38*9c5db199SXin Li jobdirs = [] 39*9c5db199SXin Li 40*9c5db199SXin Li for dir in os.listdir(path): 41*9c5db199SXin Li # skip directories not matching the job result dir pattern 42*9c5db199SXin Li if not regex.match(dir): 43*9c5db199SXin Li continue 44*9c5db199SXin Li 45*9c5db199SXin Li dir = os.path.join(options.resultsdir, dir) 46*9c5db199SXin Li if (os.path.isdir(dir) 47*9c5db199SXin Li and not os.path.exists(os.path.join(dir, PUBLISH_FLAGFILE))): 48*9c5db199SXin Li jobdirs.append(dir) 49*9c5db199SXin Li 50*9c5db199SXin Li return jobdirs 51*9c5db199SXin Li 52*9c5db199SXin Li 53*9c5db199SXin Lidef publish_job(jobdir): 54*9c5db199SXin Li cmd = RSYNC_COMMAND % (jobdir, options.dest) 55*9c5db199SXin Li utils.system(cmd) 56*9c5db199SXin Li 57*9c5db199SXin Li # mark the jobdir as published 58*9c5db199SXin Li fd = open(os.path.join(jobdir, PUBLISH_FLAGFILE), 'w') 59*9c5db199SXin Li fd.close() 60*9c5db199SXin Li print('Published', jobdir) 61*9c5db199SXin Li 62*9c5db199SXin Li 63*9c5db199SXin Lidef main(): 64*9c5db199SXin Li jobdirs = get_job_dirs(options.resultsdir) 65*9c5db199SXin Li 66*9c5db199SXin Li afe = frontend.AFE() 67*9c5db199SXin Li # the way AFE API is right now is to give a whole list of jobs and can't 68*9c5db199SXin Li # get specific jobs so minimize the queries caching the result 69*9c5db199SXin Li finished_jobs = afe.get_jobs(finished=True) 70*9c5db199SXin Li 71*9c5db199SXin Li if options.jobname_pattern: 72*9c5db199SXin Li jobname_pattern = re.compile(options.jobname_pattern) 73*9c5db199SXin Li else: 74*9c5db199SXin Li jobname_pattern = None 75*9c5db199SXin Li 76*9c5db199SXin Li # for each unpublished possible jobdir find it in the database and see 77*9c5db199SXin Li # if it is completed 78*9c5db199SXin Li for jobdir in jobdirs: 79*9c5db199SXin Li job_id = int(os.path.basename(jobdir).split('-')[0]) 80*9c5db199SXin Li job = [job for job in finished_jobs if job.id == job_id] 81*9c5db199SXin Li 82*9c5db199SXin Li if len(job) != 1: 83*9c5db199SXin Li continue 84*9c5db199SXin Li 85*9c5db199SXin Li if jobname_pattern: 86*9c5db199SXin Li # does it match the jobname pattern? 87*9c5db199SXin Li if not jobname_pattern.match(job[0].name): 88*9c5db199SXin Li continue 89*9c5db199SXin Li 90*9c5db199SXin Li # does it match the wanted job owner 91*9c5db199SXin Li if options.job_owner and options.job_owner != job[0].owner: 92*9c5db199SXin Li continue 93*9c5db199SXin Li 94*9c5db199SXin Li publish_job(jobdir) 95*9c5db199SXin Li 96*9c5db199SXin Li 97*9c5db199SXin Liif __name__ == '__main__': 98*9c5db199SXin Li parser = optparse.OptionParser(usage=USAGE) 99*9c5db199SXin Li parser.add_option('--jobname-pattern', dest='jobname_pattern', 100*9c5db199SXin Li help='Regexp pattern to match against job names, by ' 101*9c5db199SXin Li "default there won't be any matching done", 102*9c5db199SXin Li default=None) 103*9c5db199SXin Li parser.add_option('--job-owner', dest='job_owner', default=None, 104*9c5db199SXin Li help='Job owner username to match against for the ' 105*9c5db199SXin Li 'published jobs, by default no matching is done.') 106*9c5db199SXin Li options, args = parser.parse_args() 107*9c5db199SXin Li 108*9c5db199SXin Li if len(args) < 2: 109*9c5db199SXin Li print(USAGE) 110*9c5db199SXin Li sys.exit(-1) 111*9c5db199SXin Li 112*9c5db199SXin Li options.resultsdir = args[0] 113*9c5db199SXin Li options.dest = args[1] 114*9c5db199SXin Li main() 115