Feature: rerun a task locally
This commit is contained in:
Родитель
acfe71d4fb
Коммит
12036ecc05
|
@ -4,7 +4,6 @@ certifi==2017.11.5
|
|||
chardet==3.0.4
|
||||
colorama==0.3.9
|
||||
coloredlogs==8.0
|
||||
docker==3.0.0
|
||||
humanfriendly==4.6
|
||||
idna==2.6
|
||||
isort==4.2.15
|
||||
|
@ -21,4 +20,7 @@ kubernetes==4.0.0
|
|||
websocket-client==0.40.0
|
||||
wheel==0.30.0
|
||||
|
||||
kubernetes==4.0.0
|
||||
docker==3.0.0
|
||||
|
||||
-e .
|
||||
|
|
2
setup.py
2
setup.py
|
@ -40,6 +40,8 @@ DEPENDENCIES = [
|
|||
'colorama>=0.3.9',
|
||||
'adal>=0.5.0',
|
||||
'docker~=3.0.0',
|
||||
'kubernetes~=4.0.0',
|
||||
'docker~=3.0.0'
|
||||
]
|
||||
|
||||
setup(
|
||||
|
|
|
@ -15,6 +15,7 @@ def main() -> None:
|
|||
__import__('a01.images')
|
||||
__import__('a01.config')
|
||||
__import__('a01.auth')
|
||||
__import__('a01.repo')
|
||||
parser = setup_commands()
|
||||
|
||||
args = parser.parse_args()
|
||||
|
|
|
@ -32,6 +32,14 @@ class Run(object):
|
|||
for k in to_delete:
|
||||
del self.details[k]
|
||||
|
||||
@property
|
||||
def image(self) -> str:
|
||||
return self.settings['a01.reserved.imagename']
|
||||
|
||||
@property
|
||||
def product(self) -> str:
|
||||
return self.details['a01.reserved.product']
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
result = {
|
||||
'name': self.name,
|
||||
|
|
|
@ -27,6 +27,10 @@ class Task(object): # pylint: disable=too-many-instance-attributes
|
|||
def identifier(self) -> str:
|
||||
return self.settings['classifier']['identifier']
|
||||
|
||||
@property
|
||||
def command(self) -> str:
|
||||
return self.settings['execution']['command']
|
||||
|
||||
@classmethod
|
||||
def get(cls, task_id: str) -> 'Task':
|
||||
try:
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
import sys
|
||||
import base64
|
||||
|
||||
import yaml
|
||||
import docker
|
||||
import docker.errors
|
||||
import requests
|
||||
import colorama
|
||||
from kubernetes import config as kube_config
|
||||
from kubernetes import client as kube_client
|
||||
from tabulate import tabulate
|
||||
|
||||
from a01.models import Task, Run
|
||||
from a01.cli import cmd, arg
|
||||
|
||||
# pylint: disable=too-many-statements
|
||||
|
||||
|
||||
@cmd('repo task', desc="Rerun a task locally")
|
||||
@arg('task_id', positional=True)
|
||||
@arg('live', help='Rerun in live env')
|
||||
@arg('interactive', option=['-i', '--interactive'], help='Start the container in interactive mode')
|
||||
@arg('shell', help='The shell to use for interactive mode')
|
||||
@arg('mode', help='Need a mode')
|
||||
def reproduce_task(task_id: str, live: bool = False, interactive: bool = False, shell: str = '/bin/bash',
|
||||
mode: str = None) -> None:
|
||||
task = Task.get(task_id)
|
||||
run = Run.get(task.run_id)
|
||||
|
||||
summary = {
|
||||
'name': task.name,
|
||||
'image': run.image,
|
||||
'command': task.command,
|
||||
}
|
||||
|
||||
print('\nBrief\n')
|
||||
print(tabulate(summary.items(), tablefmt='plain'))
|
||||
print()
|
||||
|
||||
try:
|
||||
client = docker.from_env()
|
||||
|
||||
if not client.images.list(run.image):
|
||||
print('Pulling the test image ...')
|
||||
client.images.pull(*(run.image.split(':')))
|
||||
else:
|
||||
print(f'Image {run.image} exists locally.')
|
||||
|
||||
print('Retrieve metadata')
|
||||
metadata = client.containers.run(run.image, 'cat /app/metadata.yml', remove=True)
|
||||
metadata = yaml.load(metadata)
|
||||
|
||||
print('Get secrets from the Kubernetes cluster')
|
||||
kube_config.load_kube_config()
|
||||
kapi = kube_client.CoreV1Api()
|
||||
|
||||
secret = kapi.read_namespaced_secret(run.product, 'a01-prod')
|
||||
repo_environment_variables = {}
|
||||
|
||||
for env in metadata['environments']:
|
||||
if env['type'] == 'secret':
|
||||
value = secret.data[env['value']]
|
||||
value = base64.b64decode(value).decode('utf-8')
|
||||
|
||||
repo_environment_variables[env["name"]] = value
|
||||
elif env['type'] == 'argument-switch-live':
|
||||
if live:
|
||||
repo_environment_variables[env["name"]] = env["value"]
|
||||
elif env['type'] == 'argument-value-mode':
|
||||
if mode:
|
||||
repo_environment_variables[env['name']] = mode
|
||||
|
||||
print('Environment:')
|
||||
print(tabulate(repo_environment_variables.items(), tablefmt='plain') + '\n')
|
||||
|
||||
if interactive:
|
||||
print('Start the container in interactive mode ...\n')
|
||||
cont = client.containers.run(run.image, shell, environment=repo_environment_variables, auto_remove=True,
|
||||
detach=True, tty=True, stdin_open=True)
|
||||
print(f'\n\nRun following command to enter the container\'s shell:')
|
||||
print(f'\n{colorama.Fore.YELLOW}docker attach {cont.name}{colorama.Fore.RESET}\n')
|
||||
print(f'\nRun following command in the container to rerun the task:')
|
||||
print(f'\n{colorama.Fore.YELLOW}{task.command}{colorama.Fore.RESET}\n\n')
|
||||
|
||||
else:
|
||||
print('Run task in local container ...\n')
|
||||
|
||||
cont = client.containers.run(run.image, task.command, environment=repo_environment_variables, detach=True)
|
||||
cont.wait()
|
||||
print('\nRun finished ...\n')
|
||||
|
||||
print(colorama.Fore.LIGHTYELLOW_EX + cont.logs().decode('utf-8') + colorama.Fore.RESET)
|
||||
cont.remove()
|
||||
|
||||
except requests.HTTPError:
|
||||
print(f'Please login the docker container registry {run.image.split("/")[0]}')
|
||||
sys.exit(1)
|
|
@ -60,16 +60,10 @@ def get_run(run_id: str, log: bool = False, recording: bool = False, recording_a
|
|||
output_in_table(tasks.get_table_view(failed=not show_all), headers=tasks.get_table_header())
|
||||
output_in_table(tasks.get_summary(), tablefmt='plain')
|
||||
|
||||
log_path_template = None
|
||||
if log or recording:
|
||||
run = a01.models.Run.get(run_id=run_id)
|
||||
log_path_template = run.get_log_path_template()
|
||||
|
||||
if log:
|
||||
for failure in tasks.get_failed_tasks():
|
||||
output_in_table(zip_longest(failure.get_table_header(), failure.get_table_view()), tablefmt='plain')
|
||||
output_in_table(failure.get_log_content(log_path_template), tablefmt='plain',
|
||||
foreground_color=colorama.Fore.CYAN)
|
||||
output_in_table(failure.get_log_content(), tablefmt='plain', foreground_color=colorama.Fore.CYAN)
|
||||
|
||||
output_in_table(tasks.get_summary(), tablefmt='plain')
|
||||
|
||||
|
@ -77,7 +71,7 @@ def get_run(run_id: str, log: bool = False, recording: bool = False, recording_a
|
|||
print()
|
||||
print('Download recordings ...')
|
||||
for task in tasks.tasks:
|
||||
task.download_recording(log_path_template, recording_az_mode)
|
||||
task.download_recording(recording_az_mode)
|
||||
|
||||
if raw:
|
||||
run = a01.models.Run.get(run_id=run_id)
|
||||
|
|
Загрузка…
Ссылка в новой задаче