This repository has been archived by the owner on Mar 22, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* initial interface for cli * add command possibility * get arguments * return cli op code 1 if no token exists * temp * add getting user selection * user selection * add ssh into non k8s host * add support for instance-id * remove unecessary logging * add simple test case * add instance_id testing for invalid ids * relax to helper function * use util functions instead of cmd * add k8s testing support * handle custom commands * fix k8s tests * add include different kinds of instances flag * add failed instance test * add test for ssh_service_id * add test for multiple instances for a service_id * todo * add help message and format of values * complicated skip_prompts * modify get_user_selection to use unique field as well as index * fix short circuit * update docstrings * fix k8s test * cleanup with skip prompts * fix container name placement * testing between prompt messages * fix tabular output and use helper functions * combined test cases * add custom container test * add some test cases * change to use goal functiosn * remove active-instance assertion * handle empty last-request-time case * fix k8s container_name specification * unecessary imports * doc string * remove print * fix test * make indexes start at 1 * failed and unhealthy show as a status * fix typo * lower case convention * mutually exclusive grouping
- Loading branch information
Kevin Tang
authored
Mar 3, 2021
1 parent
6b05a54
commit 527d4a4
Showing
11 changed files
with
595 additions
and
57 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
import collections | ||
|
||
from tabulate import tabulate | ||
|
||
from waiter import terminal | ||
from waiter.format import format_last_request_time, format_mem_field, format_memory_amount, format_status | ||
from waiter.util import is_service_current, print_error | ||
|
||
|
||
def retrieve_num_instances(service): | ||
"""Returns the total number of instances.""" | ||
instance_counts = service["instance-counts"] | ||
return instance_counts["healthy-instances"] + instance_counts["unhealthy-instances"] | ||
|
||
|
||
def format_using_current_token(service, token_etag, token_name): | ||
"""Formats the "Current?" column for the given service""" | ||
is_current = is_service_current(service, token_etag, token_name) | ||
if is_current: | ||
return terminal.success('Current') | ||
else: | ||
return 'Not Current' | ||
|
||
|
||
def format_instance_status(instance): | ||
"""Formats the "Healthy?" column for the given instance""" | ||
if instance['healthy?']: | ||
return terminal.success('Healthy') | ||
else: | ||
if instance['_status'] == 'failed': | ||
status = 'Failed' | ||
elif instance['_status'] == 'killed': | ||
status = 'Killed' | ||
else: | ||
status = 'Unhealthy' | ||
return terminal.failed(status) | ||
|
||
|
||
def tabulate_token_services(services, token_name, token_etag=None, show_index=False, summary_table=True, | ||
column_names=[]): | ||
""" | ||
:param services: list of services to be displayed as rows | ||
:param token_name: the token that the services belong to | ||
:param token_etag: token_etag determines if a the service is current, will default to service['etag'] or None | ||
:param show_index: shows index column (usually for future choice prompt) | ||
:param summary_table: provides summary table of services (e.g. Total Memory, CPUS) | ||
:param column_names: column fields to be included in table | ||
:return: tabular output string and sorted services list in descending order by last request time | ||
""" | ||
num_services = len(services) | ||
if num_services > 0: | ||
services = sorted(services, key=lambda s: s.get('last-request-time', None) or '', reverse=True) | ||
rows = [collections.OrderedDict([(key, data) | ||
for key, data in | ||
[('Index', f'[{index + 1}]'), | ||
('Service Id', s['service-id']), | ||
('Cluster', s.get('cluster', None)), | ||
('Run as user', s['effective-parameters']['run-as-user']), | ||
('Instances', retrieve_num_instances(s)), | ||
('CPUs', s['effective-parameters']['cpus']), | ||
('Memory', format_mem_field(s['effective-parameters'])), | ||
('Version', s['effective-parameters']['version']), | ||
('In-flight req.', s['request-metrics']['outstanding']), | ||
('Status', format_status(s['status'])), | ||
('Last request', format_last_request_time(s)), | ||
('Current?', | ||
format_using_current_token(s, token_etag or s.get('etag', None), | ||
token_name))] | ||
if key in column_names or show_index and key == 'Index']) | ||
for index, s in enumerate(services)] | ||
service_table = tabulate(rows, headers='keys', tablefmt='plain') | ||
if summary_table: | ||
num_failing_services = len([s for s in services if s['status'] == 'Failing']) | ||
num_instances = sum(retrieve_num_instances(s) for s in services) | ||
total_mem_usage = format_memory_amount(sum(s['resource-usage']['mem'] for s in services)) | ||
total_cpu_usage = round(sum(s['resource-usage']['cpus'] for s in services), 2) | ||
table = [['# Services', num_services], | ||
['# Failing', num_failing_services], | ||
['# Instances', num_instances], | ||
['Total Memory', total_mem_usage], | ||
['Total CPUs', total_cpu_usage]] | ||
summary_table = tabulate(table, tablefmt='plain') | ||
return f'\n\n{summary_table}\n\n{service_table}', services | ||
else: | ||
return service_table, services | ||
else: | ||
return '', services | ||
|
||
|
||
def tabulate_service_instances(instances, show_index=False, column_names=[]): | ||
""" | ||
:param instances: list of instances to be displayed | ||
:param show_index: shows index column (usually for future choice prompt) | ||
:param column_names: column names to be displayed in table | ||
:return: tabular output string | ||
""" | ||
if len(instances) > 0: | ||
rows = [collections.OrderedDict([(key, data) | ||
for key, data in | ||
[('Index', f'[{index + 1}]'), | ||
('Instance Id', inst['id']), | ||
('Host', inst['host']), | ||
('Status', format_instance_status(inst))] | ||
if key in column_names or show_index and key == 'Index']) | ||
for index, inst in enumerate(instances)] | ||
return tabulate(rows, headers='keys', tablefmt='plain') | ||
else: | ||
return '' | ||
|
||
|
||
def get_user_selection(items, tabular_str, short_circuit_choice=True): | ||
""" | ||
:param items: list of possible choices | ||
:param tabular_str: table output to provide user with options | ||
:param short_circuit_choice: When True and only one item in items, return that item as the selection without user | ||
prompt. | ||
:exception Raises exception when user input is invalid | ||
:return selected item (an element from the items list) | ||
""" | ||
if short_circuit_choice and len(items) == 1: | ||
return items[0] | ||
print(tabular_str) | ||
print("testing", end='\r') | ||
answer = input(f'Enter the Index of your choice: ') | ||
print() | ||
try: | ||
index = int(answer) - 1 | ||
if index < 0 or index >= len(items): | ||
raise Exception('Input is out of range!') | ||
return items[index] | ||
except ValueError as error: | ||
print_error('Input received did not match any of the choices!') | ||
raise error |
Oops, something went wrong.