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 'starting', | |
| 18 'running', | |
| 19 'draining', | |
| 20 'drained', | |
| 21 'crashed', | |
| 22 ], | |
| 23 'desired_buildbot_state': [ | |
| 24 'offline', | |
| 25 'running', | |
| 26 'drained', | |
| 27 ], | |
| 28 'desired_transition_time_utc': [ | |
| 29 'transition_hasnt_happened', | |
| 30 'transition_happened', | |
| 31 'future_transition', | |
|
iannucci
2015/04/29 01:55:12
ready, done, future
| |
| 32 ], | |
| 33 } | |
| 34 | |
| 35 | |
| 36 def collect_evidence(master_directory, connection_timeout=30): | |
| 37 """Collects evidence from the OS for late state determination.""" | |
| 38 evidence = {} | |
| 39 evidence['now'] = timestamp.utcnow_ts() | |
| 40 evidence['last_boot'] = master.get_last_boot(master_directory) | |
| 41 evidence['last_no_new_builds'] = master.get_last_no_new_builds( | |
| 42 master_directory) | |
| 43 evidence['buildbot_is_running'] = master.buildbot_is_running(master_directory) | |
| 44 | |
| 45 if evidence['buildbot_is_running']: | |
| 46 evidence['accepting_builds'] = master.get_accepting_builds( | |
| 47 master_directory, timeout=connection_timeout) | |
| 48 | |
| 49 return evidence | |
| 50 | |
| 51 | |
| 52 def construct_pattern_matcher( | |
| 53 boot_timeout_sec=5 * 60, drain_timeout_sec=5 * 60): | |
| 54 # There is a bug in pylint which triggers false positives on decorated | |
| 55 # decorators with arguments: http://goo.gl/Ln6uyn | |
| 56 # pylint: disable=no-value-for-parameter | |
| 57 matchlist = pattern_match.MatchList(STATES) | |
| 58 | |
| 59 @matchlist.add_match( | |
|
iannucci
2015/04/29 01:55:12
what about a
@matchlist.add_match(
desired_tran
| |
| 60 buildbot='running', | |
| 61 desired_buildbot_state='running', | |
| 62 exclusions={'desired_transition_time_utc': ['transition_hasnt_happened']}) | |
|
iannucci
2015/04/29 01:55:12
what about
desired_transition_time_utc=matchlis
| |
| 63 @matchlist.add_match( | |
| 64 buildbot='running', | |
| 65 desired_transition_time_utc='future_transition') | |
| 66 @matchlist.add_match( | |
| 67 buildbot='drained', | |
| 68 desired_buildbot_state='drained', | |
| 69 exclusions={'desired_transition_time_utc': ['transition_hasnt_happened']}) | |
| 70 @matchlist.add_match( | |
| 71 buildbot='offline', | |
| 72 desired_buildbot_state='offline') | |
| 73 @matchlist.add_match( | |
| 74 buildbot='offline', | |
| 75 desired_transition_time_utc='future_transition') | |
| 76 @matchlist.add_match( | |
| 77 buildbot='starting', | |
| 78 exclusions={'desired_buildbot_state': ['offline']}) | |
| 79 @matchlist.add_match( | |
| 80 buildbot='draining') | |
| 81 def _do_nothing(): | |
| 82 return [] | |
| 83 | |
| 84 @matchlist.add_match( | |
| 85 buildbot='drained', | |
| 86 desired_buildbot_state='running') | |
| 87 @matchlist.add_match( | |
| 88 buildbot='drained', | |
| 89 desired_buildbot_state='drained', | |
| 90 desired_transition_time_utc='transition_hasnt_happened') | |
| 91 @matchlist.add_match( | |
| 92 buildbot='crashed', | |
| 93 exclusions={'desired_buildbot_state': ['offline']}) | |
| 94 def _make_restart(): | |
| 95 return [ | |
| 96 master.GclientSync, master.MakeStop, master.MakeWait, master.MakeStart] | |
| 97 | |
| 98 @matchlist.add_match( | |
| 99 buildbot='running', | |
| 100 desired_buildbot_state='running', | |
| 101 desired_transition_time_utc='transition_hasnt_happened') | |
| 102 @matchlist.add_match( | |
| 103 buildbot='running', | |
| 104 desired_buildbot_state='offline', | |
| 105 exclusions={'desired_transition_time_utc': ['future_transition']}) | |
| 106 @matchlist.add_match( | |
| 107 buildbot='running', | |
| 108 desired_buildbot_state='drained', | |
| 109 exclusions={'desired_transition_time_utc': ['future_transition']}) | |
| 110 def _make_no_new_builds(): | |
| 111 return [master.MakeNoNewBuilds] | |
| 112 | |
| 113 @matchlist.add_match( | |
| 114 buildbot='offline', | |
| 115 exclusions={ | |
| 116 'desired_buildbot_state': ['offline'], | |
| 117 'desired_transition_time_utc': ['future_transition'], | |
| 118 }) | |
| 119 def _make_start(): | |
| 120 return [master.GclientSync, master.MakeStart] | |
| 121 | |
| 122 @matchlist.add_match( | |
| 123 buildbot='crashed', | |
| 124 desired_buildbot_state='offline') | |
| 125 @matchlist.add_match( | |
| 126 buildbot='starting', | |
| 127 desired_buildbot_state='offline') | |
| 128 @matchlist.add_match( | |
| 129 buildbot='drained', | |
| 130 desired_buildbot_state='offline') | |
| 131 def _make_stop(): | |
| 132 return [master.MakeStop] | |
| 133 | |
| 134 @matchlist.add_detector('buildbot') | |
| 135 def _check_buildbot_state(data): | |
| 136 if not data['buildbot_is_running']: | |
| 137 return 'offline' | |
| 138 if data['accepting_builds'] is None: | |
|
iannucci
2015/04/29 01:55:12
later: let's invert this and call it 'draining_bui
| |
| 139 if data['last_boot'] > (data['now'] - boot_timeout_sec): | |
| 140 return 'starting' | |
| 141 return 'crashed' | |
| 142 if data['accepting_builds']: | |
| 143 return 'running' | |
| 144 if data['last_no_new_builds'] > (data['now'] - drain_timeout_sec): | |
| 145 return 'draining' | |
| 146 return 'drained' | |
| 147 | |
| 148 @matchlist.add_detector('desired_buildbot_state') | |
| 149 def _check_desired_state(data): | |
| 150 desired_state = data['desired_buildbot_state']['desired_state'] | |
| 151 if desired_state in STATES['desired_buildbot_state']: | |
| 152 return desired_state | |
| 153 | |
| 154 raise ValueError('%s is not a valid desired_buildbot_state' % desired_state) | |
| 155 | |
| 156 @matchlist.add_detector('desired_transition_time_utc') | |
| 157 def _check_transition_time(data): | |
| 158 transition_time = data['desired_buildbot_state']['transition_time_utc'] | |
| 159 if transition_time > data['now']: | |
| 160 return 'future_transition' | |
| 161 if transition_time >= data['last_boot']: | |
| 162 return 'transition_hasnt_happened' | |
| 163 return 'transition_happened' | |
| 164 | |
| 165 | |
| 166 assert matchlist.is_correct | |
| 167 return matchlist | |
| OLD | NEW |