Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(216)

Side by Side Diff: infra/services/master_manager_launcher/desired_state_parser.py

Issue 1128783003: Add master_manager_launch script which launches master_manager scripts for each master on a host. (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: Address agable's comments. Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 #!/usr/bin/python
2 # Copyright 2015 Google Inc. All Rights Reserved.
3 # pylint: disable=F0401
4
5 """Parse, validate and query the desired master state json."""
6
7 import bisect
8 import json
9 import logging
10 import operator
11 import os
12
13 from infra.libs.buildbot import master
14 from infra.libs.time_functions import timestamp
15 from infra.services.master_lifecycle import buildbot_state
16
17
18 LOGGER = logging.getLogger(__name__)
19
20
21 class InvalidDesiredMasterState(ValueError):
22 pass
23
24
25 def load_desired_state_file(filename):
26 with open(filename) as f:
27 desired_state = json.load(f)
28 if not desired_master_state_is_valid(desired_state):
29 raise InvalidDesiredMasterState()
30 return desired_state
31
32
33 def desired_master_state_is_valid(desired_state):
34 """Verify that the desired_master_state file is valid."""
35 now = timestamp.utcnow_ts()
36
37 for mastername, states in desired_state.iteritems():
38 # Verify desired_state and timestamp are valid.
39 for state in states:
40 # Verify desired_state and transition_time_utc are present.
41 for k in ('desired_state', 'transition_time_utc'):
42 if not k in state:
43 LOGGER.error(
44 'one or more states for master %s do not contain %s',
45 mastername, k)
46 return False
47
48 # Verify the desired state is in the allowed set.
49 if (state['desired_state'] not in
50 buildbot_state.STATES['desired_buildbot_state']):
51 LOGGER.error(
52 'desired_state \'%s\' is not one of %s',
53 state['desired_state'],
54 buildbot_state.STATES['desired_buildbot_state'])
55 return False
56
57 # Verify the timestamp is a number.
58 if not isinstance(state['transition_time_utc'], (int, float)):
59 LOGGER.error(
60 'transition_time_utc \'%s\' is not an int or float',
61 state['transition_time_utc'])
62 return False
63
64 # Verify the list is properly sorted.
65 sorted_states = sorted(
66 states, key=operator.itemgetter('transition_time_utc'))
67 if sorted_states != states:
68 LOGGER.error('master %s does not have states sorted by timestamp',
69 mastername)
70 LOGGER.error('should be:\n%s', json.dumps(sorted_states, indent=2))
71 return False
72
73 # Verify there is at least one state in the past.
74 if not get_master_state(states, now=now):
75 LOGGER.error(
76 'master %s does not have a state older than %s', mastername, now)
77 return False
78
79 return True
80
81
82 def get_master_state(states, now=None):
83 """Returns the latest state earlier than the current (or specified) time.
84
85 If there are three items, each with transition times of 100, 200 and 300:
86 * calling when 'now' is 50 will return None
87 * calling when 'now' is 150 will return the first item
88 * calling when 'now' is 400 will return the third item
89 """
90 now = now or timestamp.utcnow_ts()
91
92 times = [x['transition_time_utc'] for x in states]
93 index = bisect.bisect_left(times, now)
94 if index > 0: # An index of 0 means all timestamps are in the future.
95 return states[index - 1]
96 return None
97
98
99 def get_masters_for_host(desired_state, build_dir, hostname):
100 """Identify which masters on this host should be managed.
101
102 Returns triggered_masters and ignored_masters (a list and a set respectively).
103
104 triggered_masters are masters on this host which have a corresponding entry in
105 the desired_master_state file. Any master running assigned to this host that
106 does *not* have an entry in the desired_master_state file is considered
107 'ignored.'
108
109 triggered_masters is a list of dicts. Each dict is the full dict from
110 mastermap.py with two extra keys: 'fulldir' (the absolute path to the master
111 directory), and 'states' (a list of desired states sorted by transition time,
112 pulled from the desired states file).
113
114 ignored_masters is a set of 'dirname' strings (ex: master.chromium).
115 """
116 triggered_masters = []
117 ignored_masters = set()
118 for master_dict in master.get_mastermap_for_host(
119 build_dir, hostname):
120 if master_dict['dirname'] in desired_state:
121 if master_dict['internal']:
122 master_dir = os.path.abspath(os.path.join(
123 build_dir, os.pardir, 'build_internal', 'masters',
124 master_dict['dirname']))
125 else:
126 master_dir = os.path.abspath(os.path.join(
127 build_dir, 'masters', master_dict['dirname']))
128 master_dict['fulldir'] = master_dir
129 master_dict['states'] = desired_state[master_dict['dirname']]
130
131 triggered_masters.append(master_dict)
132 else:
133 ignored_masters.add(master_dict['dirname'])
134 return triggered_masters, ignored_masters
OLDNEW
« no previous file with comments | « infra/services/master_manager_launcher/__main__.py ('k') | infra/services/master_manager_launcher/test/__init__.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698