blob: a44f65f02d729673f1b8c56527ab48022e8a265e [file] [log] [blame]
Gwendal Grignou4cf71ad2015-05-13 14:21:29 -07001# Copyright 2015 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Sequence extensions to server_job.
6Adds ability to schedule jobs on given machines.
7"""
8
Simran Basied9ee482015-09-29 15:17:26 -07009import logging
Simran Basia5522a32015-10-06 11:01:24 -070010import os
Simran Basied9ee482015-09-29 15:17:26 -070011
Gwendal Grignou4cf71ad2015-05-13 14:21:29 -070012import common
13from autotest_lib.client.common_lib import control_data
Allen Li352b86a2016-12-14 12:11:27 -080014from autotest_lib.client.common_lib import priorities
Simran Basied9ee482015-09-29 15:17:26 -070015from autotest_lib.server import utils
Simran Basia5522a32015-10-06 11:01:24 -070016from autotest_lib.server.cros.dynamic_suite import control_file_getter
Gwendal Grignou4cf71ad2015-05-13 14:21:29 -070017from autotest_lib.server.cros.dynamic_suite import frontend_wrappers
18from autotest_lib.site_utils import job_directories
19
20MINUTE_IN_SECS = 60
21HOUR_IN_MINUTES = 60
22HOUR_IN_SECS = HOUR_IN_MINUTES * MINUTE_IN_SECS
23DAY_IN_HOURS = 24
24DAY_IN_SECS = DAY_IN_HOURS*HOUR_IN_SECS
25
26DEFAULT_JOB_TIMEOUT_IN_MINS = 4 * HOUR_IN_MINUTES
27
28class SequenceJob(object):
29 """Define part of a sequence that will be scheduled by the sequence test."""
30
31 CONTROL_FILE = """
32def run(machine):
Simran Basied9ee482015-09-29 15:17:26 -070033 job.run_test('%s', host=hosts.create_host(machine), client_ip=machine%s)
Gwendal Grignou4cf71ad2015-05-13 14:21:29 -070034
35parallel_simple(run, machines)
36"""
37
Simran Basia5522a32015-10-06 11:01:24 -070038 def __init__(self, name, args=None, iteration=1, duration=None,
39 fetch_control_file=False):
Gwendal Grignou4cf71ad2015-05-13 14:21:29 -070040 """
41 Constructor
42
Simran Basia5522a32015-10-06 11:01:24 -070043 @param name: name of the server test to run.
Gwendal Grignou4cf71ad2015-05-13 14:21:29 -070044 @param args: arguments needed by the server test.
45 @param iteration: number of copy of this test to sechudle
46 @param duration: expected duration of the test (in seconds).
Simran Basia5522a32015-10-06 11:01:24 -070047 @param fetch_control_file: If True, fetch the control file contents
48 from disk. Otherwise uses the template
49 control file.
Gwendal Grignou4cf71ad2015-05-13 14:21:29 -070050 """
51 self._name = name
52 self._args = args or {}
53 self._iteration = iteration
54 self._duration = duration
Simran Basia5522a32015-10-06 11:01:24 -070055 self._fetch_control_file = fetch_control_file
Gwendal Grignou4cf71ad2015-05-13 14:21:29 -070056
57
58 def child_job_name(self, machine, iteration_number):
59 """
60 Return a name for a child job.
61
62 @param machine: machine name on which the test will run.
63 @param iteration_number: number with 0 and self._iteration - 1.
64
65 @returns a unique name based on the machine, the name and the iteration.
66 """
67 name_parts = [machine, self._name]
68 tag = self._args.get('tag')
69 if tag:
70 name_parts.append(tag)
71 if self._iteration > 1:
72 name_parts.append(str(iteration_number))
73 return '_'.join(name_parts)
74
75
76 def child_job_timeout(self):
77 """
78 Get the child job timeout in minutes.
79
80 @param args: arguments sent to the test.
81
82 @returns a timeout value for the test, 4h by default.
83 """
84 if self._duration:
85 return 2 * int(self._duration) / MINUTE_IN_SECS
86 # default value:
87 return DEFAULT_JOB_TIMEOUT_IN_MINS
88
89
90 def child_control_file(self):
91 """
Simran Basia5522a32015-10-06 11:01:24 -070092 Generate the child job's control file.
Gwendal Grignou4cf71ad2015-05-13 14:21:29 -070093
Simran Basia5522a32015-10-06 11:01:24 -070094 If not fetching the contents, use the template control file and
95 populate the template control file with the test name and expand the
96 arguments list.
Gwendal Grignou4cf71ad2015-05-13 14:21:29 -070097
98 @param test: name of the test to run
99 @param args: dictionary of argument for this test.
100
101 @returns a fully built control file to be use for the child job.
102 """
Simran Basia5522a32015-10-06 11:01:24 -0700103 if self._fetch_control_file:
104 # TODO (sbasi): Add arg support.
105 cntl_file_getter = control_file_getter.FileSystemGetter(
106 [os.path.join(os.path.dirname(os.path.realpath(__file__)),
107 '..')])
108 return cntl_file_getter.get_control_file_contents_by_name(
109 self._name)
Simran Basied9ee482015-09-29 15:17:26 -0700110 child_args = ['',]
Gwendal Grignou4cf71ad2015-05-13 14:21:29 -0700111 for arg, value in self._args.iteritems():
112 child_args.append('%s=%s' % (arg, repr(value)))
113 if self._duration:
114 child_args.append('duration=%d' % self._duration)
115 return self.CONTROL_FILE % (self._name, ', '.join(child_args))
116
117
118 def schedule(self, job, timeout_mins, machine):
119 """
120 Sequence a job on the running AFE.
121
122 Will schedule a given test on the job machine(s).
123 Support a subset of tests:
124 - server job
125 - no hostless.
126 - no cleanup around tests.
127
128 @param job: server_job object that will server as parent.
129 @param timeout_mins: timeout to set up: if the test last more than
130 timeout_mins, the test will fail.
131 @param machine: machine to run the test on.
132
133 @returns a maximal time in minutes that the sequence can take.
134 """
135 afe = frontend_wrappers.RetryingAFE(timeout_min=30, delay_sec=10,
136 user=job.user, debug=False)
Prathmesh Prabhu5ad4d652018-05-11 17:33:17 -0700137 # job_directores.get_job_id_or_task_id() will return a non-int opaque id
138 # for Chrome OS Skylab tasks. But sequences will break in that case
139 # anyway, because they try to create AFE jobs internally.
140 current_job_id = int(
141 job_directories.get_job_id_or_task_id(job.resultdir))
Simran Basied9ee482015-09-29 15:17:26 -0700142 logging.debug('Current job id: %s', current_job_id)
Gwendal Grignou4cf71ad2015-05-13 14:21:29 -0700143 runtime_mins = self.child_job_timeout()
Simran Basi527c55f2015-12-14 11:57:17 -0800144 hostname = utils.get_hostname_from_machine(machine)
Gwendal Grignou4cf71ad2015-05-13 14:21:29 -0700145
146 for i in xrange(0, self._iteration):
Simran Basi527c55f2015-12-14 11:57:17 -0800147 child_job_name = self.child_job_name(hostname, i)
Simran Basied9ee482015-09-29 15:17:26 -0700148 logging.debug('Creating job: %s', child_job_name)
Gwendal Grignou4cf71ad2015-05-13 14:21:29 -0700149 afe.create_job(
150 self.child_control_file(),
Simran Basied9ee482015-09-29 15:17:26 -0700151 name=child_job_name,
Allen Li352b86a2016-12-14 12:11:27 -0800152 priority=priorities.Priority.DEFAULT,
Gwendal Grignou4cf71ad2015-05-13 14:21:29 -0700153 control_type=control_data.CONTROL_TYPE.SERVER,
Simran Basi527c55f2015-12-14 11:57:17 -0800154 hosts=[hostname], meta_hosts=(), one_time_hosts=(),
Allen Li20a5d8b2017-02-01 17:10:59 -0800155 synch_count=None, is_template=False,
Gwendal Grignou4cf71ad2015-05-13 14:21:29 -0700156 timeout_mins=timeout_mins + (i + 1) * runtime_mins,
157 max_runtime_mins=runtime_mins,
158 run_verify=False, email_list='', dependencies=(),
159 reboot_before=None, reboot_after=None,
160 parse_failed_repair=None,
161 hostless=False, keyvals=None,
162 drone_set=None, image=None,
163 parent_job_id=current_job_id, test_retry=0, run_reset=False,
Simran Basied9ee482015-09-29 15:17:26 -0700164 require_ssp=utils.is_in_container())
Gwendal Grignou4cf71ad2015-05-13 14:21:29 -0700165 return runtime_mins * self._iteration
166
167
168def sequence_schedule(job, machines, server_tests):
169 """
170 Schedule the tests to run
171
172 Launch all the tests in the sequence on all machines.
173 Returns as soon as the jobs are launched.
174
175 @param job: Job running.
176 @param machines: machine to run on.
177 @param server_tests: Array of sequence_test objects.
178 """
179 for machine in machines:
180 timeout_mins = 0
181 for test in server_tests:
182 timeout_mins += test.schedule(job, timeout_mins, machine)