Source code for idmtools_platform_local.cli.utils

"""idmtools local platform cli utils.

Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
"""

from math import floor
from typing import Dict
from colorama import Fore, Back
from idmtools_platform_local.config import DATA_PATH
from idmtools_platform_local.infrastructure.service_manager import DockerServiceManager
from idmtools_platform_local.status import Status

status_text_color_map = dict(failed=Fore.RED, in_progress=Fore.YELLOW, done=Fore.GREEN, canceled=Fore.CYAN)
status_progress_color_map = dict(failed=Back.RED, in_progress=Back.YELLOW, done=Back.GREEN, canceled=Fore.CYAN)

tags_help = "Tag to filter by. This should be in the form name value. For example, if you have a tag type=PythonTask " \
            "you would use --tags type PythonTask. In addition, you can provide multiple tags, ie --tags a 1 " \
            "--tags b 2. This will perform an AND based query on the tags meaning only jobs caontain ALL the tags " \
            "specified will be displayed"


[docs]def get_service_info(service_manger: DockerServiceManager, diff: bool, logs: bool) -> str: """ Get info about services for statusing. Args: service_manger: Service manager to use diff:Should we run a diff on the container. logs: Should logs be used Returns: Local platform container info. """ info = [] for service in ['redis', 'postgres', 'workers']: info.append(f'\n{service}\n{"=" * 20}') container = service_manger.get(service, create=False) if container: info.append(f'id: {container.id}') info.append(f'image: {container.image}') info.append(f'name: {container.name}') info.append(f'status: {container.status}') [info.append(f'{k}: {v}') for k, v in container.attrs.items()] if container.status == 'running' and service in ['workers']: info.append("Var Run") for d in ['/var/run/', '/data']: code, result = container.exec_run(f'ls -al {d}') info.append(f'\n{d}') info.extend(result.decode('utf-8').split("\n")) if logs: info.extend(container.logs().decode('utf-8').split("\n")) if diff: info.append("Diff:\n") diff = container.diff() if diff: info.append(container.diff()) else: info.append('Not running') return "\n".join(info)
[docs]def colorize_status(status: Status) -> str: """ Colorizes a status for the console. Args: status (Status): Status to colorize Returns: str: Unicode colorized string of the status """ if str(status) in status_text_color_map: status = status_text_color_map[str(status)] + str(status) + Fore.WHITE else: status = str(status) return status
[docs]def parent_status_to_progress(status: Dict[Status, int], width: int = 12) -> str: """ Convert a status object into a colorized progress bar for the console. Args: status (Dict[Status, int]): Status dictionary. The dictionary should Status values for keys and the values should be the total number of simulations in the specific status. An example would be {Status.done: 30, Status.created: 1} width (int): The desired width of the progress bar Returns: str: Progress bar of the status """ result = '' if status: if type(status) is list: # assume a list is a dict of statuses status_dict = dict() [status_dict.update(v) for v in status] status = status_dict status = {str(k): v for k, v in status.items()} total = sum([v for k, v in status.items()]) result = '' used = 0 total_complete_or_failed = sum([v for k, v in status.items() if k in ['failed', 'done']]) status_order = ['done', 'in_progress', 'failed'] for label in status_order: if label in status: w = floor(status[label] / total * width) if w > 0: color = status_progress_color_map[label] result += color + (' ' * w) used += w # add the remaining in progress if width - used > 0: result += Back.WHITE + (' ' * (width - used)) result += Back.RESET result = '[' + result + ']' + '{0}/{1} ({2:.1f}%)'.format(total_complete_or_failed, total, total_complete_or_failed / total * 100.0) return result
[docs]def urlize_data_path(path: str) -> str: """ URL-ize a data-path so it can be made click-able in the console(if the console supports it). Args: path (str): path to urilze Returns: str: Path as URL. """ return path.replace(DATA_PATH, 'http://localhost:5000/data')