feat: server kompose setup

pull/118/head
corpulent 3 years ago
parent 00462b27a7
commit 65b6a7eea7

@ -17,7 +17,9 @@ api_urls = [
path("projects/", project.ProjectListCreateAPIView.as_view()),
path("projects/import/", project.ProjectImportAPIView.as_view()),
path("projects/<str:uuid>/", project.ProjectGenericAPIView.as_view()),
path("generate/", generate.GenerateGenericAPIView.as_view()),
path("generate/", generate.GenerateDockerComposeView.as_view()),
path("generate/docker-compose", generate.GenerateDockerComposeView.as_view()),
path("generate/kubernetes", generate.GenerateK8sView.as_view()),
path("auth/self/", user.UserGenericAPIView.as_view()),
path("auth/", include("dj_rest_auth.urls")),
path("auth/github/", auth.GitHubLogin.as_view(), name="github_login"),

@ -1,11 +1,31 @@
import re
import io
import shutil
import json
import subprocess as sp
from ruamel.yaml import YAML
from pathlib import Path
from rest_framework import generics, status
from rest_framework.response import Response
from .utils import (
generate, clean_dict, get_random_string, read_dir)
from .utils import generate
def generate_docker_compose(data):
version = data.get('version', '3')
services = data.get('services', None)
volumes = data.get('volumes', None)
networks = data.get('networks', None)
return generate(
services,
volumes,
networks,
version=version,
return_format='yaml')
class GenerateGenericAPIView(generics.GenericAPIView):
class GenerateDockerComposeView(generics.GenericAPIView):
permission_classes = []
def get(self, request):
@ -13,18 +33,64 @@ class GenerateGenericAPIView(generics.GenericAPIView):
def post(self, request, format=None):
request_data = json.loads(request.data)
version = request_data['data'].get('version', '3')
services = request_data['data'].get('services', None)
volumes = request_data['data'].get('volumes', None)
networks = request_data['data'].get('networks', None)
code = generate(
services,
volumes,
networks,
version=version,
return_format='yaml')
code = generate_docker_compose(request_data["data"])
resp = {'code': code}
return Response(resp, status=status.HTTP_200_OK)
class GenerateK8sView(generics.GenericAPIView):
permission_classes = []
def get(self, request):
return Response({}, status=status.HTTP_404_NOT_FOUND)
def post(self, request, format=None):
resp = {
'code': "",
'error': ""
}
workdir = f"/tmp/{get_random_string(8)}"
request_data = json.loads(request.data)
omitted = clean_dict(request_data["data"], ["env_file", "build", "secrets"])
docker_compose_code = generate_docker_compose(omitted)
path = Path(workdir)
path.mkdir(exist_ok=True)
with open(f"{path}/docker-compose.yaml", 'w') as f:
f.write(docker_compose_code)
process = sp.Popen([
"kompose",
"--suppress-warnings",
"--file",
f"{path}/docker-compose.yaml", "convert"
], cwd=workdir, stdout=sp.PIPE, stderr=sp.PIPE)
process.wait()
_, out = process.communicate()
if out:
out = out.decode("utf-8")
parts = out.split(" ")
parts.pop()
parts.pop(0)
final_list = [re.sub(r'\[.*?;.*?m', '', x) for x in parts if any(x)]
resp["error"] = " ".join(final_list)
workdir_files = read_dir(workdir)
workdir_files.remove("docker-compose.yaml")
for file in workdir_files:
with open(f"{workdir}/{file}") as f:
yaml = YAML()
yaml.indent(mapping=2, sequence=4, offset=2)
yaml.explicit_start = True
data = yaml.load(f)
del data["metadata"]["annotations"]
del data["spec"]["template"]["metadata"]["annotations"]
buf = io.BytesIO()
yaml.dump(data, buf)
resp["code"] = buf.getvalue()
shutil.rmtree(workdir)
return Response(resp, status=status.HTTP_200_OK)

@ -1,5 +1,8 @@
import io
import os
import contextlib
import random
import string
from ruamel.yaml import YAML
from ruamel.yaml.scalarstring import DoubleQuotedScalarString
@ -58,11 +61,11 @@ def sequence_indent_one(s):
return ret_val
def get_version(verion):
def get_version(version):
try:
return int(verion)
return int(version)
except ValueError:
return float(verion)
return float(version)
def generate(services, volumes, networks, version="3", return_format='yaml'):
if return_format != 'yaml':
@ -95,8 +98,23 @@ def generate(services, volumes, networks, version="3", return_format='yaml'):
if volumes:
ret_yaml.dump({'volumes': volumes}, s)
s.write('\n')
s.seek(0)
return s.read()
def clean_dict(dic, omit=None):
if type(dic) is dict:
for key, item in dic.copy().items():
if omit and key in omit:
del dic[key]
elif type(item) is dict:
dic[key] = clean_dict(item, omit)
return dic
def get_random_string(length):
letters = string.ascii_lowercase
return ''.join(random.choice(letters) for _ in range(length))
return s
def read_dir(path):
return [f for f in os.listdir(path) if os.path.isfile(f"{path}/{f}")]

@ -6,4 +6,4 @@ class ViewGenericAPIView(generics.GenericAPIView):
permission_classes = []
def get(self, request):
return Response({}, status=status.HTTP_404_NOT_FOUND)
return Response({}, status=status.HTTP_200_OK)

@ -56,7 +56,6 @@ INSTALLED_APPS = [
"dj_rest_auth.registration",
"storages",
"corsheaders",
"axes",
"organizations",
"api",
]
@ -69,8 +68,7 @@ MIDDLEWARE = [
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"axes.middleware.AxesMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware"
]
ROOT_URLCONF = "main.urls"
@ -162,8 +160,7 @@ DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
AUTHENTICATION_BACKENDS = [
"django.contrib.auth.backends.ModelBackend",
"allauth.account.auth_backends.AuthenticationBackend",
"axes.backends.AxesBackend",
"allauth.account.auth_backends.AuthenticationBackend"
]
REST_FRAMEWORK = {

Loading…
Cancel
Save