def show(clusters, args, _): """Prints info for the token with the given token name.""" guard_no_cluster(clusters) as_json = args.get('json') as_yaml = args.get('yaml') token_name = args.get('token')[0] include_services = not args.get('no-services') query_result = query_token(clusters, token_name, include_services=include_services) if as_json or as_yaml: display_data(args, query_result) else: for cluster_name, entities in sorted(query_result['clusters'].items()): services = entities['services'] if include_services else [] print( tabulate_token(cluster_name, entities['token'], token_name, services, entities['etag'])) print() if query_result['count'] > 0: return 0 else: if not as_json and not as_yaml: print_no_data(clusters) return 1
def create_or_update_token(clusters, args, _, action): """Creates (or updates) a Waiter token""" guard_no_cluster(clusters) logging.debug('args: %s' % args) token_name_from_args = args.pop('token', None) json_file = args.pop('json', None) if json_file: if len(args) > 0: raise Exception( 'You cannot specify both a token JSON file and token field flags at the same time.' ) token_fields = load_json_file(json_file) if not token_fields: raise Exception(f'Unable to load token JSON from {json_file}.') else: token_fields = args token_name_from_json = token_fields.pop('token', None) if token_name_from_args and token_name_from_json: raise Exception( 'You cannot specify the token name both as an argument and in the token JSON file.' ) token_name = token_name_from_args or token_name_from_json if not token_name: raise Exception( 'You must specify the token name either as an argument or in a token JSON file via --json.' ) if len(clusters) > 1: default_for_create = [ c for c in clusters if c.get('default-for-create', False) ] num_default_create_clusters = len(default_for_create) if num_default_create_clusters == 0: raise Exception( 'You must either specify a cluster via --cluster or set "default-for-create" to true for ' 'one of your configured clusters.') elif num_default_create_clusters > 1: raise Exception( 'You have "default-for-create" set to true for more than one cluster.' ) else: cluster = default_for_create[0] query_result = query_token(clusters, token_name) if query_result['count'] > 0: cluster_names_with_token = list( query_result['clusters'].keys()) if cluster['name'] not in cluster_names_with_token: cluster = next(c for c in clusters if c['name'] == cluster_names_with_token[0]) logging.debug(f'token already exists in: {cluster}') else: cluster = clusters[0] return create_or_update(cluster, token_name, token_fields, action)
def create_or_update_token(clusters, args, _, action): """Creates (or updates) a Waiter token""" guard_no_cluster(clusters) logging.debug('args: %s' % args) token_name_from_args = args.pop('token', None) json_file = args.pop('json', None) yaml_file = args.pop('yaml', None) input_file = args.pop('input', None) if input_file or json_file or yaml_file: token_fields_from_json = load_data({'data': input_file, 'json': json_file, 'yaml': yaml_file}) else: token_fields_from_json = {} token_fields_from_args = args shared_keys = set(token_fields_from_json).intersection(token_fields_from_args) if shared_keys: raise Exception(f'You cannot specify the same parameter in both an input file ' f'and token field flags at the same time ({", ".join(shared_keys)}).') token_fields = {**token_fields_from_json, **token_fields_from_args} token_name_from_json = token_fields.pop('token', None) if token_name_from_args and token_name_from_json: raise Exception('You cannot specify the token name both as an argument and in the input file.') token_name = token_name_from_args or token_name_from_json if not token_name: raise Exception('You must specify the token name either as an argument or in an input file via ' '--json or --yaml.') if len(clusters) > 1: default_for_create = [c for c in clusters if c.get('default-for-create', False)] num_default_create_clusters = len(default_for_create) if num_default_create_clusters == 0: raise Exception('You must either specify a cluster via --cluster or set "default-for-create" to true for ' 'one of your configured clusters.') elif num_default_create_clusters > 1: raise Exception('You have "default-for-create" set to true for more than one cluster.') else: cluster = default_for_create[0] query_result = query_token(clusters, token_name) if query_result['count'] > 0: cluster_names_with_token = list(query_result['clusters'].keys()) if cluster['name'] not in cluster_names_with_token: cluster = next(c for c in clusters if c['name'] == cluster_names_with_token[0]) logging.debug(f'token already exists in: {cluster}') else: cluster = clusters[0] return create_or_update(cluster, token_name, token_fields, action)
def tokens(clusters, args, _): """Prints info for the tokens owned by the given user.""" guard_no_cluster(clusters) as_json = args.get('json') user = args.get('user') query_result = query_tokens(clusters, user) if as_json: print(json.dumps(query_result)) else: print_as_table(query_result) if query_result['count'] > 0: return 0 else: if not as_json: print_no_data(clusters) return 1
def ping(clusters, args, _): """Pings the token with the given token name.""" guard_no_cluster(clusters) token_name_or_service_id = args.get('token-or-service-id') is_service_id = args.get('is-service-id', False) if is_service_id: query_result = query_service(clusters, token_name_or_service_id) else: query_result = query_token(clusters, token_name_or_service_id) if query_result['count'] == 0: print_no_data(clusters) return 1 timeout = args.get('timeout', None) wait_for_request = args.get('wait', True) http_util.set_retries(0) cluster_data_pairs = sorted(query_result['clusters'].items()) clusters_by_name = {c['name']: c for c in clusters} overall_success = True for cluster_name, data in cluster_data_pairs: cluster = clusters_by_name[cluster_name] if is_service_id: success = ping_service_on_cluster(cluster, token_name_or_service_id, timeout, wait_for_request) else: token_data = data['token'] token_etag = data['etag'] token_cluster_name = token_data['cluster'].upper() if len(clusters) == 1 or token_explicitly_created_on_cluster( cluster, token_cluster_name): success = ping_token_on_cluster(cluster, token_name_or_service_id, timeout, wait_for_request, token_etag) else: print( f'Not pinging token {terminal.bold(token_name_or_service_id)} ' f'in {terminal.bold(cluster_name)} ' f'because it was created in {terminal.bold(token_cluster_name)}.' ) success = True overall_success = overall_success and success return 0 if overall_success else 1
def tokens(clusters, args, _): """Prints info for the tokens owned by the given user.""" guard_no_cluster(clusters) as_json = args.get('json') as_yaml = args.get('yaml') user = args.get('user') query_result = query_tokens(clusters, user) if as_json or as_yaml: display_data(args, query_result) else: print_as_table(query_result) if query_result['count'] > 0: return 0 else: if not as_json and not as_yaml: print_no_data(clusters) return 1
def ping(clusters, args, _): """Pings the token with the given token name.""" guard_no_cluster(clusters) token_name_or_service_id = args.get('token-or-service-id') is_service_id = args.get('is-service-id', False) if is_service_id: query_result = query_service(clusters, token_name_or_service_id) else: query_result = query_token(clusters, token_name_or_service_id) if query_result['count'] == 0: print_no_data(clusters) return 1 timeout = args.get('timeout', None) http_util.set_retries(0) cluster_data_pairs = sorted(query_result['clusters'].items()) clusters_by_name = {c['name']: c for c in clusters} overall_success = True for cluster_name, data in cluster_data_pairs: cluster = clusters_by_name[cluster_name] if is_service_id: health_check_endpoint = data['service']['effective-parameters']['health-check-url'] success = ping_service_on_cluster(cluster, token_name_or_service_id, health_check_endpoint, timeout) else: token_data = data['token'] token_cluster_name = token_data['cluster'].upper() if len(clusters) == 1 or token_explicitly_created_on_cluster(cluster, token_cluster_name): # We are hard-coding the default health-check-url here to /status; this could # alternatively be retrieved from /settings, but we want to skip the extra request health_check_endpoint = token_data.get('health-check-url', '/status') success = ping_token_on_cluster(cluster, token_name_or_service_id, health_check_endpoint, timeout) else: print(f'Not pinging token {terminal.bold(token_name_or_service_id)} ' f'in {terminal.bold(cluster_name)} ' f'because it was created in {terminal.bold(token_cluster_name)}.') success = True overall_success = overall_success and success return 0 if overall_success else 1
def delete(clusters, args, _): """Deletes the token with the given token name.""" guard_no_cluster(clusters) token_name = args.get('token')[0] query_result = query_token(clusters, token_name) if query_result['count'] == 0: print_no_data(clusters) return 1 cluster_data_pairs = sorted(query_result['clusters'].items()) num_clusters = len(cluster_data_pairs) clusters_by_name = {c['name']: c for c in clusters} if num_clusters == 1: cluster_name = cluster_data_pairs[0][0] token_etag = cluster_data_pairs[0][1]['etag'] cluster = clusters_by_name[cluster_name] success = delete_token_on_cluster(cluster, token_name, token_etag) return 0 if success else 1 elif num_clusters > 1: overall_success = True cluster_names_found = [p[0] for p in cluster_data_pairs] print( f'Token {terminal.bold(token_name)} exists in {num_clusters} clusters: {", ".join(cluster_names_found)}.' ) for cluster_name, data in cluster_data_pairs: if args.get('force', False): should_delete = True else: should_delete = str2bool( input(f'Delete token in {terminal.bold(cluster_name)}? ')) if should_delete: cluster = clusters_by_name[cluster_name] success = delete_token_on_cluster(cluster, token_name, data['etag']) overall_success = overall_success and success return 0 if overall_success else 1
def _get_existing_token_data(clusters, token_name): guard_no_cluster(clusters) cluster = get_cluster_with_token(clusters, token_name) existing_token_data, existing_token_etag = get_token(cluster, token_name) return cluster, existing_token_data, existing_token_etag
def kill(clusters, args, _): """Kills the service(s) using the given token name.""" guard_no_cluster(clusters) token_name_or_service_id = args.get('token-or-service-id') is_service_id = args.get('is-service-id', False) if is_service_id: query_result = query_service(clusters, token_name_or_service_id) num_services = query_result['count'] if num_services == 0: print_no_data(clusters) return 1 else: query_result = query_services(clusters, token_name_or_service_id) num_services = query_result['count'] if num_services == 0: clusters_text = ' / '.join( [terminal.bold(c['name']) for c in clusters]) print( f'There are no services using token {terminal.bold(token_name_or_service_id)} in {clusters_text}.' ) return 1 elif num_services > 1: print( f'There are {num_services} services using token {terminal.bold(token_name_or_service_id)}:' ) cluster_data_pairs = sorted(query_result['clusters'].items()) clusters_by_name = {c['name']: c for c in clusters} overall_success = True for cluster_name, data in cluster_data_pairs: if is_service_id: service = data['service'] service['service-id'] = token_name_or_service_id services = [service] else: services = sorted( data['services'], key=lambda s: s.get('last-request-time', None) or '', reverse=True) for service in services: service_id = service['service-id'] cluster = clusters_by_name[cluster_name] status_string = service['status'] status = format_status(status_string) inactive = status_string == 'Inactive' should_kill = False if args.get('force', False) or num_services == 1: should_kill = True else: url = urljoin(cluster['url'], f'apps/{service_id}') if is_service_id: active_instances = service['instances']['active-instances'] healthy_count = len( [i for i in active_instances if i['healthy?']]) unhealthy_count = len( [i for i in active_instances if not i['healthy?']]) else: healthy_count = service['instance-counts'][ 'healthy-instances'] unhealthy_count = service['instance-counts'][ 'unhealthy-instances'] last_request_time = format_last_request_time(service) run_as_user = service['service-description']['run-as-user'] table = [['Status', status], ['Healthy', healthy_count], ['Unhealthy', unhealthy_count], ['URL', url], ['Run as user', run_as_user]] table_text = tabulate(table, tablefmt='plain') print( f'\n' f'=== {terminal.bold(cluster_name)} / {terminal.bold(service_id)} ===\n' f'\n' f'Last Request: {last_request_time}\n' f'\n' f'{table_text}\n') if not inactive: answer = input( f'Kill service in {terminal.bold(cluster_name)}? ') should_kill = str2bool(answer) if inactive: print( f'Service {terminal.bold(service_id)} on {terminal.bold(cluster_name)} cannot be killed because ' f'it is already {status}.') should_kill = False if should_kill: success = kill_service_on_cluster(cluster, service_id, args['timeout']) overall_success = overall_success and success return 0 if overall_success else 1