From 73c1115e6fba24b86eca1e5cad5f5086d6bd2ba6 Mon Sep 17 00:00:00 2001 From: Panu Oksiala Date: Mon, 22 Jan 2024 00:24:37 +0200 Subject: Initial commit --- desmo_api/actions.py | 205 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 desmo_api/actions.py (limited to 'desmo_api/actions.py') diff --git a/desmo_api/actions.py b/desmo_api/actions.py new file mode 100644 index 0000000..767acbc --- /dev/null +++ b/desmo_api/actions.py @@ -0,0 +1,205 @@ +from __future__ import annotations + +import asyncio +import logging +import os + +import ansible_runner +from typing import TYPE_CHECKING, Optional + +if TYPE_CHECKING: + from .fsm import JailStateMachine + +from . import hcloud_dns, db, models + +logger = logging.getLogger(__name__) + + +def get_inventory(vars: Optional[dict] = None) -> dict: + return { + "all": { + "vars": { + "ansible_user": "automation", + "ansible_python_interpreter": "/usr/local/bin/python", + "jails_path": "/usr/local/jails", + "media_path": "/usr/local/jails/media", + "containers_path": "/usr/local/jails/containers", + "ansible_ssh_common_args": "-o StrictHostKeyChecking=no", + **(vars or {}), + }, + "children": { + "bsd_servers": { + "hosts": { + "bsd-1.hki-rok.atk.works": {}, + "bsd-2.hki-rok.atk.works": {}, + "bsd-3.hki-rok.atk.works": {}, + }, + } + }, + } + } + + +def run_ansible_playbook(name, playbook: str, inventory: dict): + data_dir = f"/tmp/ansible-isolation/{name}" + os.makedirs(data_dir, exist_ok=True) + with open(os.environ["SSH_KEY_FILE"], "r") as f: + ssh_key = f.read() + return ansible_runner.run_async( + private_data_dir=data_dir, + project_dir=f"{os.getcwd()}/ansible/project", + playbook=playbook, + inventory=inventory, + ssh_key=ssh_key, + ) + + +async def jail_provisioning(jail_info: models.JailInfo): + vars = { + "jail_host": jail_info.host, + "jail_name": jail_info.name, + "jail_ipv6": jail_info.ip, + } + inventory = get_inventory(vars) + _thread, runner = run_ansible_playbook( + jail_info.name, "create_jail.yaml", inventory + ) + while runner.rc is None: + await asyncio.sleep(1) + if runner.rc != 0: + raise Exception(f"Ansible failed with {runner.rc}") + + +async def start_jail_provisioning(fsm: JailStateMachine, database: db.DB, name: str): + logger.info("Starting provisioning for jail %s", name) + try: + jail_info = await database.get_jail(name) + await jail_provisioning(jail_info=jail_info) + fsm.jail_provisioned() + except Exception as e: + logger.error("Jail provisioning failed for %s", name, exc_info=e) + fsm.jail_provisioning_failed() + + +async def dns_provisioning( + dns_client: hcloud_dns.HCloudDNS, jail_info: models.JailInfo +): + zone_id = os.environ["HCLOUD_DNS_ZONE_ID"] + name = jail_info.name + ipv6 = jail_info.ip + records = await dns_client.get_records_by_name(zone_id, name) + for record in records: + logger.info("Deleting existing record %s for jail %s", record.id, name) + await dns_client.delete_record(record.id) + + logger.info("Creating AAAA record for jail %s", name) + await dns_client.create_record( + zone_id=zone_id, + name=f"{name}.jail", + record_type="AAAA", + value=ipv6, + ) + + +async def start_dns_provisioning( + fsm: JailStateMachine, + database: db.DB, + dns_client: hcloud_dns.HCloudDNS, + name: str, +): + logger.info("Starting DNS provisioning for jail %s", name) + try: + jail_info = await database.get_jail(name) + await dns_provisioning(dns_client, jail_info) + fsm.dns_provisioned() + except Exception as e: + logger.error("DNS provisioning failed for server %s", name, exc_info=e) + fsm.dns_provisioning_failed() + + +async def jail_setup( + jail_info: models.JailInfo, packages: list[str], commands: list[str] +): + vars = { + "jail_host": jail_info.host, + "jail_name": jail_info.name, + "jail_packages": packages, + "jail_commands": commands, + } + inventory = get_inventory(vars) + _thread, runner = run_ansible_playbook(jail_info.name, "setup_jail.yaml", inventory) + while runner.rc is None: + await asyncio.sleep(1) + if runner.rc != 0: + raise Exception(f"Ansible failed with {runner.rc}") + + +async def start_jail_setup(fsm: JailStateMachine, database: db.DB, name: str): + logger.info("Starting jail setup for jail %s", name) + try: + jail_info = await database.get_jail(name) + packages = await database.get_jail_packages(name) + commands = await database.get_jail_commands(name) + await jail_setup(jail_info=jail_info, packages=packages, commands=commands) + fsm.jail_setup_done() + except Exception as e: + logger.error("Jail setup failed for jail %s", name, exc_info=e) + fsm.jail_setup_failed() + + +async def start_jail_watch(fsm: JailStateMachine, database: db.DB, name: str): + logger.info("Starting healtcheck for jail %s", name) + try: + logger.info("not implemented lol") + except Exception as e: + logger.error("Server healtcheck failed for jail %s", name, exc_info=e) + + +async def jail_removal(jail_info: models.JailInfo): + vars = { + "jail_host": jail_info.host, + "jail_name": jail_info.name, + } + inventory = get_inventory(vars) + _thread, runner = run_ansible_playbook( + jail_info.name, "delete_jail.yaml", inventory + ) + while runner.rc is None: + await asyncio.sleep(1) + if runner.rc != 0: + raise Exception(f"Ansible failed with {runner.rc}") + + +async def start_jail_removal(fsm: JailStateMachine, database: db.DB, name: str): + logger.info("Starting removal of jail %s", name) + try: + jail_info = await database.get_jail(name) + await jail_removal(jail_info) + fsm.jail_removed() + except Exception as e: + logger.error("Stop server failed for server %s, ignoring", name, exc_info=e) + fsm.jail_removal_failed() + + +async def dns_deprovisioning(dns_client: hcloud_dns.HCloudDNS, name: str): + zone_id = os.environ["HCLOUD_DNS_ZONE_ID"] + + records = await dns_client.get_records_by_name(zone_id, f"{name}.jail") + for record in records: + logger.info("Deleting record %s for jail %s", record.id, name) + await dns_client.delete_record(record.id) + + +async def start_dns_deprovisioning( + fsm: JailStateMachine, dns_client: hcloud_dns.HCloudDNS, database: db.DB, name: str +): + logger.info("Starting DNS deprovisioning for jail %s", name) + try: + await dns_deprovisioning(dns_client, name) + await database.set_jail_state( + name, "terminated" + ) # Have to do this here because the tasks will be cancelled + fsm.dns_deprovisioned() + except Exception as e: + logger.error("DNS deprovisioning failed for jail %s", name, exc_info=e) + fsm.dns_deprovisioning_failed() -- cgit v1.3