import datetime import uuid from docker import from_env from docker.models.containers import Container import json from fastapi import BackgroundTasks import utils.db from utils.models import Execution docker = from_env() def run_workflow(workflow:str, bg_tasks:BackgroundTasks) -> dict: db_session = utils.db.SessionLocal() try: with open("config/"+workflow+".json") as workflow_file: workflow_data_raw = workflow_file.read() workflow_data = json.loads(workflow_data_raw) ongoing_execution = ( db_session.query(Execution) .filter(Execution.workflow_name == workflow) .filter(Execution.status != 3) .filter(Execution.status != 4) .filter(Execution.status != -1) .first() ) if ongoing_execution: return {"status":"error","error":"workflow_already_running"} container:Container = docker.containers.run( workflow_data['image'], detach=True, command=workflow_data['start_cmd'], volumes=['/var/run/docker.sock:/var/run/docker.sock'], working_dir="/usr/ci-repo" ) execution = Execution( workflow_name=workflow, total_commands=len(workflow_data['steps']) ) db_session.add(execution) db_session.commit() bg_tasks.add_task(run_tasks, workflow_data=workflow_data, container=container,execution_id=execution.id) return {"status":"container_created","container_id":container.id,"execution_id":execution.id} except Exception as e: print("uh oh something broke") #TODO: hey idiot make this better with sentry and a nice return and stuff return {"status":"error","error":"idk"} finally: db_session.close() def run_tasks(workflow_data:dict, container:Container, execution_id: uuid.UUID): db_session = utils.db.SessionLocal() try: execution = db_session.query(Execution).filter(Execution.id == execution_id).first() execution.status = 1 db_session.commit() cmd_results = [] cmd_result = container.exec_run("apk add git") cmd_results.append({ "command":"apk add git", "code":cmd_result.exit_code, "output":cmd_result.output.decode(), "context": "init_command" }) execution.execution_data = cmd_results db_session.commit() if workflow_data.get('repo_clone_enabled'): command = "git clone "+workflow_data['repo_url']+" ." cmd_result = container.exec_run(command) cmd_results.append({ "command": command, "code": cmd_result.exit_code, "output": cmd_result.output.decode(), "context": "init_command" }) execution.execution_data = cmd_results execution.status = 2 db_session.commit() for step in workflow_data['steps']: cmd_result = container.exec_run(step['cmd'],environment=step.get('env')) cmd_results.append({ "command": step['cmd'], "code": cmd_result.exit_code, "output": cmd_result.output.decode() }) execution.execution_data = cmd_results db_session.commit() if cmd_result.exit_code != 0: execution.status = 4 db_session.commit() break execution.finish_time = datetime.datetime.now() db_session.commit() container.stop() container.remove() if execution.status == 2: execution.status = 3 db_session.commit() except Exception as e: try: # try to set the execution status if stuff goes wrong execution = db_session.query(Execution).filter(Execution.id == execution_id).first() execution.status = -1 db_session.commit() except Exception: pass raise e finally: db_session.close()