def parse_args(parser, argv=None): """Parse aguments.""" # Parse general arguments, extract the command, add command-specific # arguments, and then re-parse everything again. # The argparse module provides subparser support, and we could have # used that. However, there a serious usability issue with that, because # "command <subcmd> --foo" is an error if --foo is a valid argument # for command but not for the sub-command. Given that is very common # to mistakenly pass options out of order, we imlement our own solution # here that accepts the options in this case. try: args = parser.parse_args(argv) except argparse.ParseError as e: args = e.namespace if not (args.help or args.version) and not args.subcmd: console.write_err(parser.format_usage()) console.error(str(e)) error.exit(error.EX_USAGE) if args.help and not args.subcmd: console.write_err(parser.format_help()) error.exit(error.EX_OK) if args.version and not args.subcmd: console.writeln_err(_version.version_string) error.exit(error.EX_OK) subcmd = args.subcmd if subcmd not in subcommands: console.error("Unknown command: '{0}'.", subcmd) error.exit(error.EX_USAGE) add_args = subcommands[subcmd][1] add_args(parser) try: args = parser.parse_args(argv) except argparse.ParseError as e: args = e.namespace if not args.help: console.write_err(parser.format_usage()) console.error(str(e)) error.exit(error.EX_USAGE) if args.help: console.write_err(parser.format_help()) error.exit(error.EX_OK) return args
def main(argv=None): """The "ravtest" main entry point.""" if sys.platform.startswith('win'): console.error('Windows is not currently supported by "ravtest".\n' 'Please use the Fabric front-end.') error.exit(1) parser = create_parser() args = parse_args(parser, argv) create_environment(args) setup_logging() command = subcommands[args.subcmd][0] try: ret = command(args, env) except KeyboardInterrupt: console.complete_partial_line() console.writeln('Exiting at user request.') ret = error.EX_INTERRUPTED except SystemExit as e: console.complete_partial_line() if env.debug: console.error('SystemExit caught') lines = traceback.format_exception(*sys.exc_info()) console.writeln_err('Raised from:') console.writeln_err(''.join(lines)) ret = e[0] except Exception as e: console.complete_partial_line() console.error(str(e)) if env.debug: lines = ['An uncaught exception occurred:'] lines += traceback.format_exception(*sys.exc_info()) console.writeln_err() console.writeln_err(''.join(lines)) console.writeln_err('Environment: {!r}'.format(env)) ret = getattr(e, 'exitstatus', error.EX_SOFTWARE) return ret
def run_all_tasks(app, vms): """Run the runbook for an application ``app``.""" hosts = [] host_info = {} appname = app['name'].split(':')[1] for appdef in env.manifest['applications']: if appdef['name'] == appname: break else: error.raise_error('Application definition not found?') for vm in app['vms']: if vm['name'] not in vms: continue ipaddr = vm['dynamicMetadata']['externalIp'] hosts.append(ipaddr) host_info[ipaddr] = vm['name'] env.test_id = os.urandom(16).encode('hex') console.info('Starting run `{0}`.', env.test_id) env.host_info = host_info env.start_time = int(time.time()) env.lock = multiprocessing.Lock() manager = multiprocessing.Manager() env.shared_state = manager.dict() for vmname in vms: vmstate = {} vmstate['exited'] = False vmstate['completed_tasks'] = {} vmstate['shell_env_update'] = {} env.shared_state[vmname] = vmstate env.appdef = appdef env.application = app env.vms = vms fab.env.user = '******' fab.env.key_filename = env.private_key_file fab.env.disable_known_hosts = True fab.env.remote_interrupt = True fab.env.hosts = hosts fab.env.parallel = True fab.env.output_prefix = env.debug fabric.state.output.running = env.debug fabric.state.output.output = True fabric.state.output.status = env.debug # This is where it all happens... noun = inflect.plural_noun('virtual machine', len(vms)) console.info('Executing tasks on {0} {1}...', len(vms), noun) fabric.tasks.execute(run_tasklist, env) errors = set() for vmname in vms: vmstate = env.shared_state[vmname] for taskname,status in vmstate['completed_tasks'].items(): if status != 0: errors.add('`{0}` on `{1}`'.format(taskname, vmname)) if not errors: console.info('All tasks were executed succesfully!') else: what = inflect.plural_noun('task', len(errors)) errapps = ', '.join(errors) console.error('The following {0} failed: {1}', what, errapps) fabric.network.disconnect_all() return len(errors)