Refactor and add a number of helper methods

This commit is contained in:
Luke Murphy 2020-07-02 12:23:48 +02:00
parent ae06f928bf
commit ad31f17888
No known key found for this signature in database
GPG Key ID: 5E2EF5A63E3718CC
1 changed files with 53 additions and 31 deletions

View File

@ -4,8 +4,11 @@ from json import dumps, loads
from os import environ from os import environ
from os.path import exists from os.path import exists
from pathlib import Path from pathlib import Path
from random import choice
from shlex import split from shlex import split
from string import ascii_lowercase
from subprocess import run from subprocess import run
from typing import Dict
from flask import Flask, render_template, request from flask import Flask, render_template, request
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
@ -22,37 +25,25 @@ APPS = {"gitea": "https://git.autonomic.zone/compose-stacks/gitea"}
DATA_DIR = Path("./data") DATA_DIR = Path("./data")
class GiteaConfigForm(FlaskForm): def get_secret(n: int) -> str:
app_name = StringField("Application name", default="Gitea") """Generate a ASCII secret that is n chars long."""
db_host = StringField("Database host", default="mariadb:3306") return "".join(choice(ascii_lowercase) for _ in range(n))
db_name = StringField("Database name", default="gitea")
db_passwd = PasswordField("Database password", validators=[DataRequired()])
db_root_passwd = PasswordField(
"Root database password", validators=[DataRequired()]
)
db_type = StringField("Database type", default="mysql")
db_user = StringField("Database user", default="mysql")
domain = StringField("Domain name", validators=[DataRequired()])
ssh_port = StringField("SSH port", default="2222")
stack_name = StringField("Stack name", default="gitea")
internal_token = PasswordField("Internal token", validators=[DataRequired()])
jwt_secret = PasswordField("JWT secret", validators=[DataRequired()])
def clone_app_template(app_name): def clone_app_template(app_name: str) -> None:
"""Git clone an app template repository.""" """Git clone an app template repository."""
clone_path = DATA_DIR / app_name clone_path = DATA_DIR / app_name
clone_url = apps[app_name] clone_url = APPS[app_name]
run(split(f"git clone {clone_url} {clone_path}")) run(split(f"git clone {clone_url} {clone_path}"))
def dump_db(db): def dump_db(db: Dict) -> None:
"""Dump the database.""" """Dump the database."""
with open(DATA_DIR / "db.json", "w") as handle: with open(DATA_DIR / "db.json", "w") as handle:
return handle.write(dumps(db)) handle.write(dumps(db))
def load_db(): def load_db() -> Dict:
"""Load the database.""" """Load the database."""
db_path = DATA_DIR / "db.json" db_path = DATA_DIR / "db.json"
if exists(db_path): if exists(db_path):
@ -61,33 +52,64 @@ def load_db():
return {} return {}
def stack_deploy(app_name, env):
"""Depoy an application to the swarm."""
compose_yml = DATA_DIR / app_name / "compose.yml"
command = f"docker stack deploy -c {compose_yml} {app_name}"
run(split(command), env=env)
def get_loaded_env(app_name, request_form):
"""Load an environment with install form values for compose.yml injection."""
environment = environ.copy()
for key in request_form.keys():
environment[key.upper()] = request.form[key]
return environment
class GiteaInstallForm(FlaskForm):
"""Gitea installation form."""
app_name = StringField("Application name", default="Git with a cup of tea")
domain = StringField("Domain name", validators=[DataRequired()])
db_host = StringField("Database host", default="mariadb:3306")
db_name = StringField("Database name", default="gitea")
db_passwd = PasswordField("DB password", default=get_secret(n=32))
db_root_passwd = PasswordField("Root DB password", default=get_secret(n=32))
db_type = StringField("Database type", default="mysql")
db_user = StringField("Database user", default="mysql")
internal_token = PasswordField("Internal token", default=get_secret(n=105))
jwt_secret = PasswordField("JWT secret", default=get_secret(n=43))
secret_key = PasswordField("Secret key", default=get_secret(n=64))
ssh_port = StringField("SSH port", default="2222")
@app.route("/") @app.route("/")
def index(): def index():
"""Home page for app installation possibilities."""
return render_template("second/index.html", apps=[app for app in APPS]) return render_template("second/index.html", apps=[app for app in APPS])
@app.route("/config/<app_name>") @app.route("/install/<app_name>")
def config(app_name): def install(app_name):
"""Installation page for an app."""
if app_name == "gitea": if app_name == "gitea":
# Note(decentral1se): load db.json and pre-populate the form? form = GiteaInstallForm()
form = GiteaConfigForm() return render_template("second/install.html", app_name=app_name, form=form)
return render_template("second/config.html", app_name=app_name, form=form)
@app.route("/deploy/<app_name>", methods=["POST"]) @app.route("/deploy/<app_name>", methods=["POST"])
def deploy(app_name): def deploy(app_name):
environment = environ.copy() """Deployment end-point for an app."""
for key in request.form.keys(): environment = get_loaded_env(app_name, request.form)
environment[key.upper()] = request.form[key]
# Note(decentral1se): how to handle the following? # Note(decentral1se): how to handle the following?
# configs -> ${STACK_NAME}_app_ini_${APP_INI_VERSION} # configs -> ${STACK_NAME}_app_ini_${APP_INI_VERSION}
# secrets -> ${STACK_NAME}_db_passwd_${DB_PASSWD_VERSION} # secrets -> ${STACK_NAME}_db_passwd_${DB_PASSWD_VERSION}
# and dump it all to the db.json when we're done here too # and dump it all to the db.json when we're done here too
compose_yml = DATA_DIR / app_name / "compose.yml" stack_deploy(app_name, environment)
command = f"docker stack deploy -c {compose_yml} {app_name}"
run(split(command), env=environment)
if __name__ == "__main__": if __name__ == "__main__":