def handle(self, client, parser): auth = parser.add_argument_group('OAuth2.0 Options') auth.add_argument('--description', help='description of the generated OAuth2.0 token', metavar='TEXT') auth.add_argument('--conf.client_id', metavar='TEXT') auth.add_argument('--conf.client_secret', metavar='TEXT') auth.add_argument('--conf.scope', choices=['read', 'write'], default='write') if client.help: self.print_help(parser) raise SystemExit() parsed = parser.parse_known_args()[0] kwargs = { 'client_id': getattr(parsed, 'conf.client_id', None), 'client_secret': getattr(parsed, 'conf.client_secret', None), 'scope': getattr(parsed, 'conf.scope', None), } if getattr(parsed, 'description', None): kwargs['description'] = parsed.description try: token = api.Api().get_oauth2_token(**kwargs) except Exception as e: self.print_help(parser) cprint( 'Error retrieving an OAuth2.0 token ({}).'.format(e.__class__), 'red') else: fmt = client.get_config('format') if fmt == 'human': print('export CONTROLLER_OAUTH_TOKEN={}'.format(token)) else: print(to_str(FORMATTERS[fmt]({'token': token}, '.')).strip())
def parse_resource(self, skip_deprecated=False): """Attempt to parse the <resource> (e.g., jobs) specified on the CLI If a valid resource is discovered, the user will be authenticated (either via an OAuth2.0 token or session-based auth) and the remaining CLI arguments will be processed (to determine the requested action e.g., list, create, delete) :param skip_deprecated: when False (the default), deprecated resource names from the open source tower-cli project will be allowed """ self.resource = parse_resource(self, skip_deprecated=skip_deprecated) if self.resource: self.authenticate() resource = getattr(self.v2, self.resource) if is_control_resource(self.resource): # control resources are special endpoints that you can only # do an HTTP GET to, and which return plain JSON metadata # examples are `/api/v2/ping/`, `/api/v2/config/`, etc... if self.help: self.subparsers[self.resource].print_help() raise SystemExit() self.method = 'get' response = getattr(resource, self.method)() else: response = self.parse_action(resource) _filter = self.get_config('filter') # human format for metrics, settings is special if self.resource in ('metrics', 'settings' ) and self.get_config('format') == 'human': response.json = { 'count': len(response.json), 'results': [{ 'key': k, 'value': v } for k, v in response.json.items()] } _filter = 'key, value' if self.get_config( 'format' ) == 'human' and _filter == '.' and self.resource in UNIQUENESS_RULES: _filter = ', '.join(UNIQUENESS_RULES[self.resource]) formatted = format_response(response, fmt=self.get_config('format'), filter=_filter, changed=self.original_action in ('modify', 'create', 'associate', 'disassociate')) if formatted: print(utils.to_str(formatted), file=self.stdout) if hasattr(response, 'rc'): raise SystemExit(response.rc) else: self.parser.print_help()
def run(stdout=sys.stdout, stderr=sys.stderr, argv=[]): cli = CLI(stdout=stdout, stderr=stderr) try: cli.parse_args(argv or sys.argv) cli.connect() cli.parse_resource() except KeyboardInterrupt: sys.exit(1) except ConnectionError as e: cli.parser.print_help() msg = ( '\nThere was a network error of some kind trying to reach ' '{}.\nYou might need to specify (or double-check) ' '--conf.host'.format(cli.get_config('host')) ) if isinstance(e, SSLError): msg = ( '\nCould not establish a secure connection. ' '\nPlease add your server to your certificate authority.' '\nYou can also run this command by specifying ' '-k or --conf.insecure' ) cprint(msg + '\n', 'red', file=stderr) cprint(e, 'red', file=stderr) sys.exit(1) except Unauthorized as e: cli.parser.print_help() msg = '\nValid credentials were not provided.\n$ awx login --help' cprint(msg + '\n', 'red', file=stderr) if cli.verbose: cprint(e.__class__, 'red', file=stderr) sys.exit(1) except Common as e: if cli.verbose: print(traceback.format_exc(), sys.stderr) if cli.get_config('format') == 'json': json.dump(e.msg, sys.stdout) print('') elif cli.get_config('format') == 'yaml': sys.stdout.write(to_str( yaml.safe_dump( e.msg, default_flow_style=False, encoding='utf-8', allow_unicode=True ) )) elif cli.get_config('format') == 'human': sys.stdout.write(e.__class__.__name__) print('') sys.exit(1) except Exception as e: if cli.verbose: e = traceback.format_exc() cprint(e, 'red', file=stderr) sys.exit(1)
def fetch(next_line): for result in events(**payload).json.results: if result['start_line'] != next_line: # If this event is a line from _later_ in the stdout, # it means that the events didn't arrive in order; # skip it for now and wait until the prior lines arrive and are # printed continue stdout = to_str(result.get('stdout')) if stdout and print_stdout: print(stdout) next_line = result['end_line'] return next_line
def parse_resource(self, skip_deprecated=False): """Attempt to parse the <resource> (e.g., jobs) specified on the CLI If a valid resource is discovered, the user will be authenticated (either via an OAuth2.0 token or session-based auth) and the remaining CLI arguments will be processed (to determine the requested action e.g., list, create, delete) :param skip_deprecated: when False (the default), deprecated resource names from the open source tower-cli project will be allowed """ self.resource = parse_resource(self, skip_deprecated=skip_deprecated) if self.resource: self.authenticate() resource = getattr(self.v2, self.resource) if is_control_resource(self.resource): # control resources are special endpoints that you can only # do an HTTP GET to, and which return plain JSON metadata # examples are `/api/v2/ping/`, `/api/v2/config/`, etc... if self.help: self.subparsers[self.resource].print_help() raise SystemExit() self.method = 'get' response = getattr(resource, self.method)() else: response = self.parse_action(resource) formatted = format_response( response, fmt=self.get_config('format'), filter=self.get_config('filter'), changed=self.original_action in ( 'modify', 'create', 'associate', 'disassociate' ) ) if formatted: print(utils.to_str(formatted), file=self.stdout) else: self.parser.print_help() if six.PY2 and not self.help: # Unfortunately, argparse behavior between py2 and py3 # changed in a notable way when required subparsers # have invalid (or missing) arguments specified # see: https://github.com/python/cpython/commit/f97c59aaba2d93e48cbc6d25f7ff9f9c87f8d0b2 print('\nargument resource: invalid choice') raise SystemExit(2)
def fetch(seen): results = response.connection.get('/api/v2/unified_jobs', payload).json()['results'] # erase lines we've previously printed if print_stdout and sys.stdout.isatty(): for _ in seen: sys.stdout.write('\x1b[1A') sys.stdout.write('\x1b[2K') for result in results: result['name'] = to_str(result['name']) if print_stdout: print(' ↳ {id} - {name} '.format(**result), end='') status = result['status'] if color_enabled(): color = STATUS_COLORS.get(status, 'white') cprint(status, color) else: print(status) seen.add(result['id'])
def monitor_workflow(response, session, print_stdout=True, timeout=None, interval=0.25): get = response.url.get payload = { 'order_by': 'finished', 'unified_job_node__workflow_job': response.id, } def fetch(seen): results = response.connection.get('/api/v2/unified_jobs', payload).json()['results'] # erase lines we've previously printed if print_stdout and sys.stdout.isatty(): for _ in seen: sys.stdout.write('\x1b[1A') sys.stdout.write('\x1b[2K') for result in results: result['name'] = to_str(result['name']) if print_stdout: print(' ↳ {id} - {name} '.format(**result), end='') status = result['status'] if color_enabled(): color = STATUS_COLORS.get(status, 'white') cprint(status, color) else: print(status) seen.add(result['id']) if print_stdout: cprint('------Starting Standard Out Stream------', 'red') if print_stdout: print('Launching {}...'.format(to_str(get().json.name))) started = time.time() seen = set() while True: if timeout and time.time() - started > timeout: if print_stdout: cprint('Monitoring aborted due to timeout.', 'red') break if sys.stdout.isatty(): # if this is a tty-like device, we can send ANSI codes # to draw an auto-updating view # otherwise, just wait for the job to finish and print it *once* # all at the end fetch(seen) time.sleep(0.25) json = get().json if json.finished: fetch(seen) break if print_stdout: cprint('------End of Standard Out Stream--------\n', 'red') return get().json.status
def __init__(self, endpoint, connection): self.endpoint = to_str(endpoint) self.connection = connection
def __new__(cls, endpoint, connection): return super(TentativePage, cls).__new__(cls, to_str(endpoint))