Chromium Code Reviews| Index: infra/services/master_manager_launcher/__main__.py |
| diff --git a/infra/services/master_manager_launcher/__main__.py b/infra/services/master_manager_launcher/__main__.py |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..245c3fab67b456276c782a2036d4bafe3cfc3c64 |
| --- /dev/null |
| +++ b/infra/services/master_manager_launcher/__main__.py |
| @@ -0,0 +1,122 @@ |
| +#!/usr/bin/python |
| +# Copyright 2015 Google Inc. All Rights Reserved. |
| +# pylint: disable=F0401 |
| + |
| +"""Launch a master_manager script for every master on a host.""" |
| + |
| +# pragma: no cover |
|
agable
2015/05/07 17:59:31
I don't think this actually works. Does it? I swea
ghost stip (do not use)
2015/05/07 19:49:39
again -- since there is no test file associated wi
agable
2015/05/08 00:14:53
Ah, right. Balls :(
|
| + |
| +import argparse |
| +import json |
| +import logging |
| +import operator |
| +import os |
| +import socket |
| +import subprocess |
| +import sys |
| + |
| +from infra.libs import logs |
| +from infra.libs.service_utils import daemon |
| +from infra.services.master_lifecycle import buildbot_state |
| +from infra.services.master_manager_launcher import desired_state_parser |
| + |
| + |
| +SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__)) |
| +RUNPY = os.path.abspath(os.path.join( |
| + SCRIPT_DIR, os.pardir, os.pardir, os.pardir, 'run.py')) |
| + |
| + |
| +def parse_args(): |
| + parser = argparse.ArgumentParser( |
| + description='Launches master_manager for every master on a host. NOTE: ' |
| + 'does not perform any action unless --prod is set.') |
| + parser.add_argument('build_dir', nargs='?', |
| + help='location of the tools/build directory') |
| + parser.add_argument('--hostname', |
| + default=socket.getfqdn(), |
| + help='override local hostname (currently %(default)s)') |
| + parser.add_argument('--json-location', |
| + default='desired_master_state.json', |
| + help='desired master state configuration (default: %(default)s)') |
| + parser.add_argument('--command-timeout', |
| + help='apply a timeout in seconds to each master_manager process') |
| + parser.add_argument('--verify', action='store_true', |
| + help='verify the desired master state JSON is valid, then exit') |
| + parser.add_argument('--prod', action='store_true', |
| + help='actually perform actions instead of doing a dry run') |
| + logs.add_argparse_options(parser) |
| + |
| + args = parser.parse_args() |
| + logs.process_argparse_options(args) |
| + |
| + if not args.verify: |
| + if not args.build_dir: |
| + parser.error('A build/ directory must be specified.') |
| + |
| + return args |
| + |
| + |
| +def synthesize_master_manager_cmd(master_dict, hostname, prod=False): |
| + """Find the current desired state and synthesize a command for the master.""" |
| + state = desired_state_parser.get_master_state(master_dict['states']) |
| + cmd = [ |
| + RUNPY, |
| + 'infra.tools.master_manager', |
| + master_dict['fulldir'], |
| + str(state['desired_state']), |
| + str(state['transition_time_utc']), |
| + '--hostname', hostname, |
| + '--enable-gclient-sync', |
| + '--verbose', |
| + ] |
| + |
| + if prod: |
| + cmd.append('--prod') |
| + |
| + return cmd |
| + |
| + |
| +def log_triggered_ignored(triggered, ignored, hostname): |
| + """Outputs for humans which masters will be managed and which won't.""" |
| + if ignored: |
| + logging.info( |
| + '%d masters on host %s left unmanaged (no desired state section):\n%s', |
| + len(ignored), hostname, '\n'.join(ignored)) |
| + |
| + triggered_master_string = '.' |
| + if triggered: |
| + triggered_master_string = ':\n' |
| + triggered_master_string += '\n'.join(m['dirname'] for m in triggered) |
| + logging.info( |
| + '%d masters managed for host %s%s', |
| + len(triggered), hostname, triggered_master_string) |
| + |
| + |
| +def main(): |
| + args = parse_args() |
| + |
| + desired_state = desired_state_parser.load_desired_state_file( |
| + args.json_location) |
| + |
| + if args.verify: |
| + return 0 # File checks out, no need to continue. |
| + |
| + triggered, ignored = desired_state_parser.get_masters_for_host( |
| + desired_state, args.build_dir, args.hostname) |
| + log_triggered_ignored(triggered, ignored, args.hostname) |
| + |
| + commands = [ |
| + synthesize_master_manager_cmd(m, args.hostname, prod=args.prod) |
| + for m in triggered |
| + ] |
| + |
| + if args.command_timeout: |
| + commands = [daemon.add_timeout(c, args.command_timeout) for c in commands] |
| + |
| + for command in commands: |
| + logging.info('running %s' % command) |
|
agable
2015/05/07 17:59:31
This log line will be prettier (and copy-pasteable
ghost stip (do not use)
2015/05/07 19:49:39
I always worry about doing that because you might
agable
2015/05/08 00:14:53
Hmm. That's fair, I suppose. But also makes me wan
|
| + subprocess.call(command) |
| + |
| + |
| +if __name__ == '__main__': |
| + sys.exit(main()) |