deduping_scheduler.py revision b493555db2d43e79d96e793cae9d1ffb822dd6c1
1# Copyright (c) 2012 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
5import logging
6from autotest_lib.server.cros.dynamic_suite import frontend_wrappers
7from autotest_lib.server import frontend
8
9
10class DedupingSchedulerException(Exception):
11    """Base class for exceptions from this module."""
12    pass
13
14
15class ScheduleException(DedupingSchedulerException):
16    """Raised when an error is returned from the AFE during scheduling."""
17    pass
18
19
20class DedupException(DedupingSchedulerException):
21    """Raised when an error occurs while checking for duplicate jobs."""
22    pass
23
24
25class DedupingScheduler(object):
26    """A class that will schedule suites to run on a given board, build.
27
28    Includes logic to check whether or not a given (suite, board, build)
29    has already been run.  If so, it will skip scheduling that suite.
30
31    @var _afe: a frontend.AFE instance used to talk to autotest.
32    """
33
34
35    def __init__(self, afe=None):
36        """Constructor
37
38        @param afe: an instance of AFE as defined in server/frontend.py.
39                    Defaults to a frontend_wrappers.RetryingAFE instance.
40        """
41        self._afe = afe or frontend_wrappers.RetryingAFE(timeout_min=30,
42                                                         delay_sec=10,
43                                                         debug=False)
44
45
46    def _ShouldScheduleSuite(self, suite, board, build):
47        """Return True if |suite| has not yet been run for |build| on |board|.
48
49        True if |suite| has not been run for |build| on |board|.
50        False if it has been.
51
52        @param suite: the name of the suite to run, e.g. 'bvt'
53        @param board: the board to run the suite on, e.g. x86-alex
54        @param build: the build to install e.g.
55                      x86-alex-release/R18-1655.0.0-a1-b1584.
56        @return False if the suite was already scheduled, True if not
57        @raise DedupException if the AFE raises while searching for jobs.
58        """
59        try:
60            return not self._afe.get_jobs(name__startswith=build,
61                                          name__endswith='control.'+suite)
62        except Exception as e:
63            raise DedupException(e)
64
65
66    def _Schedule(self, suite, board, build, pool, num):
67        """Schedule |suite|, if it hasn't already been run.
68
69        @param suite: the name of the suite to run, e.g. 'bvt'
70        @param board: the board to run the suite on, e.g. x86-alex
71        @param build: the build to install e.g.
72                      x86-alex-release/R18-1655.0.0-a1-b1584.
73        @param pool: the pool of machines to use for scheduling purposes.
74                     Default: None
75        @param num: the number of devices across which to shard the test suite.
76                    Default: None (uses sharding factor in global_config.ini).
77        @return True if the suite got scheduled
78        @raise ScheduleException if an error occurs while scheduling.
79        """
80        try:
81            logging.info('Scheduling %s on %s against %s (pool: %s)',
82                         suite, build, board, pool)
83            if self._afe.run('create_suite_job',
84                             suite_name=suite,
85                             board=board,
86                             build=build,
87                             check_hosts=False,
88                             num=num,
89                             pool=pool) is not None:
90                return True
91            else:
92                raise ScheduleException(
93                    "Can't schedule %s for %s." % (suite, build))
94        except Exception as e:
95            raise ScheduleException(e)
96
97
98    def ScheduleSuite(self, suite, board, build, pool, num, force=False):
99        """Schedule |suite|, if it hasn't already been run.
100
101        If |suite| has not already been run against |build| on |board|,
102        schedule it and return True.  If it has, return False.
103
104        @param suite: the name of the suite to run, e.g. 'bvt'
105        @param board: the board to run the suite on, e.g. x86-alex
106        @param build: the build to install e.g.
107                      x86-alex-release/R18-1655.0.0-a1-b1584.
108        @param pool: the pool of machines to use for scheduling purposes.
109        @param num: the number of devices across which to shard the test suite.
110        @param force: Always schedule the suite.
111        @return True if the suite got scheduled, False if not
112        @raise DedupException if we can't check for dups.
113        @raise ScheduleException if the suite cannot be scheduled.
114        """
115        if force or self._ShouldScheduleSuite(suite, board, build):
116            return self._Schedule(suite, board, build, pool, num)
117        return False
118
119
120    def GetHosts(self, *args, **kwargs):
121        """Forward a request to get hosts onto the AFE instance's get_hosts."""
122        return self._afe.get_hosts(*args, **kwargs)
123