from email.quoprimime import body_check from http.client import HTTPException # from turtle import title from typing import Union, Optional from fastapi import FastAPI, Response, status, HTTPException, Request from fastapi.params import Body from fastapi.responses import HTMLResponse, PlainTextResponse from pydantic import BaseModel from random import randrange import os import subprocess # from podman import PodmanClient import json import yaml import docker from fastapi.templating import Jinja2Templates import socket import random import string dragontool = FastAPI() #uri = "unix:///run/podman/podman.sock" #uri = "http+unix://%2frun%2fpodman.sock/v4.0.0/libpod/version" #podmanapi = PodmanClient(base_url=uri) podmanapi = docker.DockerClient(base_url='unix://run/user/1000/podman/podman.sock') yaml_file = open("containers.yaml", 'r') yaml_content = yaml.load(yaml_file,Loader=yaml.FullLoader) templates = Jinja2Templates(directory="templates") class Environment(BaseModel): username: str uid: Optional[str] = None def Random_alphanumeric_string(length): return ''.join(random.choices(string.ascii_letters + string.digits,k=length)) def Filter(string, substr): return [str for str in string if any(sub in str for sub in substr)] def Unique_list(input_list): output_list = [] for word in input_list: if word not in output_list: output_list.append(word) return output_list @dragontool.get("/") async def root(): return {"message": "Welcome to Dragontool API!"} @dragontool.post("/api/v1/environments", status_code=status.HTTP_201_CREATED) async def create_environments(env: Environment): env_dict = env.dict() env_dict['username'] = env_dict['username'].replace("-", "_") if env_dict['uid'] is None: container_uid = Random_alphanumeric_string(8) else: container_uid = env_dict['uid'] try: network = podmanapi.networks.create(name=env_dict['username']+'-'+container_uid) except docker.errors.APIError: raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Server returns an error") if env_dict['username'] == "gitlab": container_timeout = "86400" else: container_timeout = "432000" for container in yaml_content['containers']: cmd = subprocess.run(["podman","run","-dt","--rm","-P","--privileged","--memory",container['memory'],"--cpus",container['cpus'],"--timeout",container_timeout,"--name",container['name']+'-'+env_dict['username']+'-'+container_uid,"--network",env_dict['username']+'-'+container_uid,"--network-alias",container['name'],container['image']+':1.0'],stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True, text=True) # try: # container = podmanapi.containers.run(image=container['image']+":1.0",name=container['name']+'-'+env_dict['username']+'-'+container_uid,privileged=True,detach=True,publish_all_ports=True, remove=True,network=env_dict['username']+'-'+container_uid) # except docker.errors.ContainerError: # raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Environment {env_dict['username']+'-'+env_dict['uid']} already in use!") # except docker.errors.ImageNotFound: # raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Image on server does not exist!") # except docker.errors.APIError: # raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Server returns an error") json_response = json.dumps({'Username': env_dict['username'],'uid': container_uid,'Creation': 'successfull'}, indent=4, default=str) return Response(content=json_response,media_type='application/json') @dragontool.post("/api/v1/environments/inventory", status_code=status.HTTP_201_CREATED, response_class=HTMLResponse) async def get_inventory(request: Request, env: Environment): env_dict = env.dict() env_dict['username'] = env_dict['username'].replace("-", "_") env_dict['uid'] = env_dict['uid'].replace("-", "_") container_list = [] for yaml_container in yaml_content['containers']: try: container = podmanapi.containers.get(yaml_container['name']+'-'+env_dict['username']+'-'+env_dict['uid']) except docker.errors.NotFound: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Environment {env_dict['username']+'-'+env_dict['uid']} not found!") except docker.errors.APIError: raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Server returns an error") for priv_port,pub_port in container.ports.items(): if priv_port == '2222/tcp': for host_port in pub_port: containers_0 = {} containers_0['container_alias'] = yaml_container['name'] containers_0['container_name'] = container.name.strip('/') containers_0['container_pub_ssh_port'] = host_port['HostPort'] containers_0['container_batch'] = yaml_container['batch'] container_list.append(containers_0) response = templates.TemplateResponse("hosts-template-v2.ini", {"request": request, "container_list": container_list, "host_ip": socket.gethostbyname(socket.gethostname()) }) return response @dragontool.post("/api/v1/environments/ports", status_code=status.HTTP_201_CREATED, response_class=HTMLResponse) async def get_ports(request: Request, env: Environment): env_dict = env.dict() env_dict['username'] = env_dict['username'].replace("-", "_") env_dict['uid'] = env_dict['uid'].replace("-", "_") container_list = [] for yaml_container in yaml_content['containers']: try: container = podmanapi.containers.get(yaml_container['name']+'-'+env_dict['username']+'-'+env_dict['uid']) except docker.errors.NotFound: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Environment {env_dict['username']+'-'+env_dict['uid']} not found!") except docker.errors.APIError: raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Server returns an error") for priv_port,pub_port in container.ports.items(): #print(priv_port,pub_port) if priv_port == '2222/tcp': for host_port in pub_port: containers_0 = {} containers_0['container_alias'] = yaml_container['name'] containers_0['container_name'] = container.name.strip('/') containers_0['container_pub_ssh_port'] = host_port['HostPort'] containers_0['host_ip'] = socket.gethostbyname(socket.gethostname()) container_list.append(containers_0) if priv_port == '3890/tcp': for host_port in pub_port: containers_0 = {} containers_0['container_alias'] = yaml_container['name'] containers_0['container_name'] = container.name.strip('/') containers_0['container_pub_ldap_port'] = host_port['HostPort'] containers_0['host_ip'] = socket.gethostbyname(socket.gethostname()) container_list.append(containers_0) json_response = json.dumps(container_list, indent=4, default=str) return Response(content=json_response,media_type='application/json') @dragontool.delete("/api/v1/environments", status_code=status.HTTP_204_NO_CONTENT) async def delete_environments(env: Environment): """ Delete environments of username + uid given """ env_dict = env.dict() env_dict['username'] = env_dict['username'].replace("-", "_") env_dict['uid'] = env_dict['uid'].replace("-", "_") for container in yaml_content['containers']: try: container = podmanapi.containers.get(container['name']+'-'+env_dict['username']+'-'+env_dict['uid']) try: container.remove(v=True,force=True) except docker.errors.APIError: pass except docker.errors.NotFound: pass except docker.errors.APIError: raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Server returns an error") try: network = podmanapi.networks.prune() except docker.errors.APIError: raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Server returns an error") try: container = podmanapi.containers.prune() except docker.errors.APIError: raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Server returns an error") try: image = podmanapi.images.prune() except docker.errors.APIError: raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Server returns an error") return Response(status_code=status.HTTP_204_NO_CONTENT) @dragontool.post("/api/v1/environments/list") async def list_environments(env: Environment): """ Restrieve environments belonging to username that is given """ env_dict = env.dict() env_dict['username'] = env_dict['username'].replace("-", "_") #env_dict['uid'] = env_dict['uid'].replace("-", "_") containers = podmanapi.containers.list(all=True) container_list = [] for container in containers: container_list.append(container.name) #print(container.status) substr = [env_dict['username']] filtered_containers = (Filter(container_list, substr)) container_list = [] for container in yaml_content['containers']: container_list.append(container['name']) filtered_containers_list = [] for filtered_container in filtered_containers: filtered_container = filtered_container.split("-", 2) filtered_containers_list.extend(filtered_container) for cont in container_list: while cont in filtered_containers_list: filtered_containers_list.remove(cont) filtered_containers_list.remove(env_dict['username']) conts_0 = Unique_list(filtered_containers_list) container_list = [] for cont_0 in conts_0: containers_0 = {} containers_0['uid'] = cont_0 container_list.append(containers_0) json_response = json.dumps(container_list, indent=4, default=str) return Response(content=json_response,media_type='application/json')