Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 # Copyright 2015 The Chromium 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 | |
| 6 """A state machine to determine and act on a buildbot master's state.""" | |
| 7 | |
| 8 | |
| 9 from infra.libs.state_machine import pattern_match | |
| 10 from infra.libs.time_functions import timestamp | |
| 11 from infra.libs.buildbot import master | |
| 12 | |
| 13 | |
| 14 STATES = { | |
| 15 'buildbot': [ | |
| 16 'offline', | |
| 17 'booting', | |
| 18 'started_serving_accept', | |
| 19 'started_serving_not_accept', | |
| 20 'started_serving_not_accept_drained', | |
| 21 'started_not_serving', | |
| 22 ], | |
| 23 'desired_buildbot_state': [ | |
|
agable
2015/04/27 20:23:08
As noted in the comments below, the desired states
ghost stip (do not use)
2015/04/29 01:30:33
After online discussion, adjusted to three dimensi
| |
| 24 'offline', | |
| 25 'future', | |
|
agable
2015/04/27 20:23:08
I have no earthly idea what "desired buildbot stat
| |
| 26 'needs_reboot', | |
|
agable
2015/04/27 20:23:08
Desired state: needs reboot? I would like this bui
| |
| 27 'up_to_date', | |
| 28 ], | |
| 29 } | |
| 30 | |
| 31 | |
| 32 def collect_evidence(master_directory, connection_timeout=30): | |
| 33 """Collects evidence from the OS for late state determination.""" | |
| 34 evidence = {} | |
| 35 evidence['now'] = timestamp.utcnow_ts() | |
| 36 evidence['last_boot'] = master.get_last_boot(master_directory) | |
| 37 evidence['last_no_new_builds'] = master.get_last_no_new_builds( | |
| 38 master_directory) | |
| 39 evidence['buildbot_is_running'] = master.buildbot_is_running(master_directory) | |
| 40 | |
| 41 if evidence['buildbot_is_running']: | |
| 42 evidence['accepting_builds'] = master.get_accepting_builds( | |
| 43 master_directory, timeout=connection_timeout) | |
| 44 | |
| 45 return evidence | |
| 46 | |
| 47 | |
| 48 def construct_pattern_matcher( | |
| 49 boot_timeout_sec=5 * 60, drain_timeout_sec=5 * 60): | |
| 50 # There is a bug in pylint which triggers false positives on decorated | |
| 51 # decorators with arguments: http://goo.gl/Ln6uyn | |
| 52 # pylint: disable=no-value-for-parameter | |
| 53 matchlist = pattern_match.MatchList(STATES) | |
| 54 | |
| 55 @matchlist.add_match( | |
| 56 buildbot='started_serving_accept', | |
| 57 desired_buildbot_state='up_to_date') | |
| 58 @matchlist.add_match( | |
| 59 buildbot='started_serving_accept', | |
| 60 desired_buildbot_state='future') | |
| 61 @matchlist.add_match( | |
| 62 buildbot='offline', | |
| 63 exclusions={'desired_buildbot_state': ['up_to_date', 'needs_reboot']}) | |
| 64 @matchlist.add_match( | |
| 65 buildbot='booting', | |
| 66 exclusions={'desired_buildbot_state': ['offline']}) | |
| 67 @matchlist.add_match( | |
| 68 buildbot='started_serving_not_accept') | |
| 69 def _do_nothing(): | |
| 70 return [] | |
| 71 | |
| 72 @matchlist.add_match( | |
| 73 buildbot='started_serving_not_accept_drained', | |
| 74 exclusions={'desired_buildbot_state': ['offline']}) | |
| 75 @matchlist.add_match( | |
| 76 buildbot='started_not_serving', | |
| 77 exclusions={'desired_buildbot_state': ['offline']}) | |
| 78 def _make_restart(): | |
| 79 return [ | |
| 80 master.GclientSync, master.MakeStop, master.MakeWait, master.MakeStart] | |
| 81 | |
| 82 @matchlist.add_match( | |
| 83 buildbot='started_serving_accept', | |
| 84 desired_buildbot_state='needs_reboot') | |
| 85 @matchlist.add_match( | |
| 86 buildbot='started_serving_accept', | |
| 87 desired_buildbot_state='offline') | |
| 88 def _make_no_new_builds(): | |
| 89 return [master.MakeNoNewBuilds] | |
| 90 | |
| 91 @matchlist.add_match( | |
| 92 buildbot='offline', | |
| 93 desired_buildbot_state='up_to_date') | |
| 94 @matchlist.add_match( | |
| 95 buildbot='offline', | |
| 96 desired_buildbot_state='needs_reboot') | |
| 97 def _make_start(): | |
| 98 return [master.GclientSync, master.MakeStart] | |
| 99 | |
| 100 @matchlist.add_match( | |
| 101 buildbot='started_not_serving', | |
| 102 desired_buildbot_state='offline') | |
| 103 @matchlist.add_match( | |
| 104 buildbot='booting', | |
| 105 desired_buildbot_state='offline') | |
| 106 @matchlist.add_match( | |
| 107 buildbot='started_serving_not_accept_drained', | |
| 108 desired_buildbot_state='offline') | |
| 109 def _make_stop(): | |
| 110 return [master.MakeStop] | |
| 111 | |
| 112 @matchlist.add_detector('buildbot') | |
| 113 def _check_buildbot_state(data): | |
| 114 if not data['buildbot_is_running']: | |
| 115 return 'offline' | |
| 116 if data['accepting_builds'] is None: | |
| 117 if data['last_boot'] > (data['now'] - boot_timeout_sec): | |
| 118 return 'booting' | |
| 119 return 'started_not_serving' | |
| 120 if data['accepting_builds']: | |
| 121 return 'started_serving_accept' | |
| 122 if data['last_no_new_builds'] > (data['now'] - drain_timeout_sec): | |
| 123 return 'started_serving_not_accept' | |
| 124 return 'started_serving_not_accept_drained' | |
| 125 | |
| 126 @matchlist.add_detector('desired_buildbot_state') | |
| 127 def _check_desired_state(data): | |
| 128 if not data['desired_buildbot_state']['desired_state']: | |
| 129 return 'offline' | |
| 130 if data['desired_buildbot_state']['desired_state'] > data['now']: | |
| 131 return 'future' | |
| 132 if not data['last_boot']: | |
| 133 return 'needs_reboot' | |
| 134 if data['desired_buildbot_state']['desired_state'] >= data['last_boot']: | |
| 135 return 'needs_reboot' | |
| 136 return 'up_to_date' | |
| 137 | |
| 138 assert matchlist.is_correct | |
| 139 return matchlist | |
| OLD | NEW |