aboutsummaryrefslogtreecommitdiffstats
path: root/desmo_api/fsm.py
diff options
context:
space:
mode:
Diffstat (limited to 'desmo_api/fsm.py')
-rw-r--r--desmo_api/fsm.py124
1 files changed, 124 insertions, 0 deletions
diff --git a/desmo_api/fsm.py b/desmo_api/fsm.py
new file mode 100644
index 0000000..dfbef20
--- /dev/null
+++ b/desmo_api/fsm.py
@@ -0,0 +1,124 @@
+import asyncio
+from collections.abc import Coroutine
+import logging
+from statemachine import StateMachine, State
+
+
+from . import actions
+from . import hcloud_dns
+from . import db
+
+
+logger = logging.getLogger(__name__)
+
+
+class JailStateMachine(StateMachine):
+ def __init__(
+ self,
+ dns_client: hcloud_dns.HCloudDNS,
+ database: db.DB,
+ name: str,
+ ):
+ self._dns_client = dns_client
+ self._name = name
+ self._db = database
+ self._tasks = set()
+
+ super().__init__()
+
+ uninitialized = State(initial=True)
+ jail_provisioning = State()
+ dns_provisioning = State()
+ jail_setup = State()
+ jail_ready = State()
+ jail_removal = State()
+ dns_deprovisioning = State()
+ terminated = State()
+
+ initialize = uninitialized.to(jail_provisioning) | terminated.to(jail_provisioning)
+ jail_provisioned = jail_provisioning.to(dns_provisioning)
+ jail_provisioning_failed = jail_provisioning.to(jail_provisioning)
+ dns_provisioned = dns_provisioning.to(jail_setup)
+ dns_provisioning_failed = dns_provisioning.to(dns_provisioning)
+ jail_setup_done = jail_setup.to(jail_ready)
+ jail_setup_failed = jail_setup.to(jail_setup)
+ remove_jail = jail_ready.to(jail_removal)
+ jail_removal_failed = jail_removal.to(jail_removal)
+ jail_removed = jail_removal.to(dns_deprovisioning)
+ dns_deprovisioned = dns_deprovisioning.to(terminated)
+ dns_deprovisioning_failed = dns_deprovisioning.to(dns_deprovisioning)
+
+ def start_on_enter_task(self):
+ state = self.current_state.id
+ switch = {
+ "jail_provisioning": self.on_enter_jail_provisioning,
+ "dns_provisioning": self.on_enter_dns_provisioning,
+ "jail_setup": self.on_enter_jail_setup,
+ "jail_ready": self.on_enter_jail_ready,
+ "jail_removal": self.on_enter_jail_removal,
+ "dns_deprovisioning": self.on_enter_dns_deprovisioning,
+ }
+ func = switch.get(state)
+ if func is not None:
+ func()
+
+ async def _store_state_and_run(self, awaitable: Coroutine):
+ await self._db.set_jail_state(self._name, self.current_state.id)
+ await awaitable
+
+ def on_enter_jail_provisioning(self):
+ task = asyncio.create_task(
+ self._store_state_and_run(
+ actions.start_jail_provisioning(self, self._db, self._name)
+ )
+ )
+ self._tasks.add(task)
+
+ def on_enter_dns_provisioning(self):
+ task = asyncio.create_task(
+ self._store_state_and_run(
+ actions.start_dns_provisioning(
+ self, self._db, self._dns_client, self._name
+ )
+ )
+ )
+ self._tasks.add(task)
+
+ def on_enter_jail_setup(self):
+ task = asyncio.create_task(
+ self._store_state_and_run(
+ actions.start_jail_setup(self, self._db, self._name)
+ )
+ )
+ self._tasks.add(task)
+
+ def on_enter_jail_ready(self):
+ task = asyncio.create_task(
+ self._store_state_and_run(
+ actions.start_jail_watch(self, self._db, self._name)
+ )
+ )
+ self._tasks.add(task)
+
+ def on_enter_jail_removal(self):
+ task = asyncio.create_task(
+ self._store_state_and_run(
+ actions.start_jail_removal(self, self._db, self._name)
+ )
+ )
+ self._tasks.add(task)
+
+ def on_enter_dns_deprovisioning(self):
+ task = asyncio.create_task(
+ self._store_state_and_run(
+ actions.start_dns_deprovisioning(
+ self, self._dns_client, self._db, self._name
+ )
+ )
+ )
+ self._tasks.add(task)
+
+ def on_enter_terminated(self):
+ logger.info("Jail %s terminated", self._name)
+ for task in self._tasks:
+ task.cancel()