aboutsummaryrefslogtreecommitdiffstats
path: root/desmo_api/actions.py
diff options
context:
space:
mode:
authorPanu Oksiala <panu@oksiala.fi>2024-01-22 00:24:37 +0200
committerPanu Oksiala <panu@oksiala.fi>2024-01-22 00:24:37 +0200
commit73c1115e6fba24b86eca1e5cad5f5086d6bd2ba6 (patch)
treedaedbc44f41c91a13cb7fc26edd325ab14996217 /desmo_api/actions.py
Initial commit
Diffstat (limited to 'desmo_api/actions.py')
-rw-r--r--desmo_api/actions.py205
1 files changed, 205 insertions, 0 deletions
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()