1
0
Fork 0
mirror of https://codeberg.org/Mo8it/AdvLabDB.git synced 2024-09-19 18:31:16 +00:00
AdvLabDB/podman/deploy.py

243 lines
7 KiB
Python
Executable file

#!/usr/bin/python3
import subprocess # nosec 404
import sys
from argparse import ArgumentParser
from pathlib import Path
# Variables
# You might want to change some.
# Volumes
VOLUMES_DIR = Path.home() / "volumes"
# AdvLabDB
ADVLABDB_REPO_LINK = "https://gitlab.rlp.net/mobitar/advlabdb.git"
ADVLABDB_VOLUMES_DIR = VOLUMES_DIR / "advlabdb"
ADVLABDB_REPO_DIR = ADVLABDB_VOLUMES_DIR / "repo"
ADVLABDB_LOGS_DIR = ADVLABDB_VOLUMES_DIR / "logs"
# Traefik
TRAEFIK_VOLUMES_DIR = VOLUMES_DIR / "traefik"
TRAEFIK_ETC_DIR = TRAEFIK_VOLUMES_DIR / "etc"
TRAEFIK_LOGS_DIR = TRAEFIK_VOLUMES_DIR / "logs"
TRAEFIK_CERTS_DIR = TRAEFIK_VOLUMES_DIR / "certs"
# Nginx
NGINX_CONF_D_DIR = VOLUMES_DIR / "nginx/conf.d"
# Systemd
SYSTEMD_USER_DIR = Path.home() / ".config/systemd/user"
# Parse script arguments
parser = ArgumentParser(
description="Build the AdvLabDB image and deploy related containers.",
)
parser.add_argument(
"--skip-traefik",
action="store_true",
help="Do not deploy the Traefik container.",
)
parser.add_argument(
"--skip-nginx",
action="store_true",
help="Do not deploy the Nginx container.",
)
parser.add_argument(
"-n",
"--network",
default="traefik",
help="Traefik's network. Default: traefik.",
)
parser.add_argument(
"-v",
"--verbose",
action="store_true",
help="Show more information while running.",
)
args = parser.parse_args()
# Functions
def run(command: str, **kwargs):
if args.verbose:
print("Running command:")
print(f"\t{command}")
return subprocess.run(command, shell=True, **kwargs) # nosec B602
# Needed for create_container
if args.verbose:
print(f"Making sure that the systemd directory for user services {SYSTEMD_USER_DIR} exists.")
SYSTEMD_USER_DIR.mkdir(parents=True, exist_ok=True)
def create_container(container_name: str, podman_args: str):
"""
Create a container with a systemd service.
"""
print(f"Creating container: {container_name}.")
run(
f"""podman create \
--name {container_name} \
--tz local \
{podman_args}""",
check=True,
)
print(f"Generating a systemd service then enabling and starting it for the container {container_name}.")
print(f"The service is a user service and named container-{container_name}.")
print("You can check its status with the following command:")
print(f"\tsystemctl --user status container-{container_name}")
run(
f"podman generate systemd --new --files --name {container_name}",
cwd=SYSTEMD_USER_DIR,
check=True,
)
run(
f"systemctl --user enable --now container-{container_name}",
check=True,
)
# Checking requirements
env_file = ADVLABDB_REPO_DIR / ".env"
if ADVLABDB_REPO_DIR.is_dir():
print("Pulling AdvLabDB repository.")
run(
"git pull origin main",
cwd=ADVLABDB_REPO_DIR,
check=True,
)
if not env_file.is_file():
sys.exit(f"{env_file} missing!")
else:
if args.verbose:
print(f"Making sure that the volumes directory {ADVLABDB_VOLUMES_DIR} exists.")
ADVLABDB_VOLUMES_DIR.mkdir(parents=True, exist_ok=True)
print("Cloning AdvLabDB repository")
print(f"From:\t{ADVLABDB_REPO_LINK}")
print(f"Into:\t{ADVLABDB_REPO_DIR}")
run(
f"git clone {ADVLABDB_REPO_LINK} {ADVLABDB_REPO_DIR}",
check=True,
)
sys.exit(f"{env_file} missing!")
if not args.skip_traefik:
if not TRAEFIK_ETC_DIR.is_dir():
sys.exit(f"{TRAEFIK_ETC_DIR} missing!")
if not args.skip_nginx:
if not NGINX_CONF_D_DIR.is_dir():
sys.exit(f"{NGINX_CONF_D_DIR} missing!")
if run(f"podman network exists {args.network}").returncode != 0:
if args.skip_traefik:
sys.exit(f"Skipped Traefik's deployment although Traefik's network {args.network} does not exist!")
else:
print(f"Creating network {args.network}.")
run(
f"podman network create {args.network}",
check=True,
)
# Create/update the AdvLabDB image and container
# Make sure that the builder container does not exist.
run(
"buildah rm builder",
stderr=subprocess.DEVNULL,
)
print("Creating AdvLabDB image.")
commands = [
# TODO: Use fixed version tag 3.10-slim
"buildah from --pull --name builder docker.io/library/python:slim",
# Copy repo into container
f"buildah copy builder {ADVLABDB_REPO_DIR} /volumes/repo",
"buildah config --workingdir /volumes/repo builder",
# Install Python requirements in the container
"buildah run builder -- pip3 install -r requirements.txt",
# TODO: Only when database does not exist
"buildah run builder -- python3 -m advlabdb.scripts.setup.init_database",
"buildah config --cmd 'gunicorn --bind 0.0.0.0:80 --workers 5 --log-file /volumes/logs/gunicorn.log run:app' builder",
]
for command in commands:
run(command, check=True)
if run("systemctl --user is-enabled container-advlabdb").returncode == 0:
print("Disabling and deleting existing container advlabdb.")
run(
"systemctl --user disable --now container-advlabdb",
check=True,
)
if run("podman image exists advlabdb").returncode == 0:
print("Deleting existing image advlabdb")
run(
"podman rmi advlabdb",
check=True,
)
# Save new image
run(
"buildah commit --rm builder advlabdb",
check=True,
)
if args.verbose:
print(f"Making sure that the logs directory {ADVLABDB_LOGS_DIR} exists.")
ADVLABDB_LOGS_DIR.mkdir(parents=True, exist_ok=True)
print("Creating container advlabdb.")
create_container(
"advlabdb",
# TODO: Add database as volume
f"""--network {args.network} \
-v {ADVLABDB_LOGS_DIR}:/volumes/logs:Z \
localhost/advlabdb:latest""",
)
# Create Traefik container if needed
if not args.skip_traefik and run("systemctl --user is-enabled container-traefik").returncode != 0:
if args.verbose:
print(f"Making sure that the logs directory {TRAEFIK_LOGS_DIR} exists.")
TRAEFIK_LOGS_DIR.mkdir(parents=True, exist_ok=True)
if args.verbose:
print(f"Making sure that the certificates directory {TRAEFIK_CERTS_DIR} exists.")
TRAEFIK_CERTS_DIR.mkdir(parents=True, exist_ok=True)
print("Creating container traefik.")
create_container(
"traefik",
f"""--label "io.containers.autoupdate=registry" \
--network {args.network} \
-p 80:80 \
-p 443:443 \
-v {TRAEFIK_ETC_DIR}:/etc/traefik:ro:Z,ro \
-v {TRAEFIK_LOGS_DIR}:/volumes/logs:Z \
-v {TRAEFIK_CERTS_DIR}:/volumes/certs:Z \
docker.io/library/traefik:latest""",
)
# Create Nginx container if needed
if not args.skip_nginx and run("systemctl --user is-enabled container-nginx").returncode != 0:
print("Creating container nginx.")
create_container(
"nginx",
f"""--label "io.containers.autoupdate=registry" \
--network {args.network} \
-v {NGINX_CONF_D_DIR}:/etc/nginx/conf.d:Z,ro \
docker.io/library/nginx:alpine""",
)
print("\nDone!\n")