Files
bunkerweb/ui/src/Instances.py
2022-06-03 17:24:14 +02:00

215 lines
6.1 KiB
Python

import os
from typing import Any
from subprocess import run
from api.API import API
from utils.ApiCaller import ApiCaller
class Instance:
_id: str
name: str
hostname: str
_type: str
health: bool
env: Any
apiCaller: ApiCaller
def __init__(
self,
_id: str,
name: str,
hostname: str,
_type: str,
status: str,
data: Any = None,
apiCaller: ApiCaller = ApiCaller(),
) -> None:
self._id = _id
self.name = name
self.hostname = hostname
self._type = _type
self.health = status == "up" and (
(
data.attrs["State"]["Health"]["Status"] == "healthy"
if "Health" in data.attrs["State"]
else False
)
if data
else True
)
self.env = data
self.apiCaller = apiCaller
def get_id(self) -> str:
return self._id
def run_jobs(self) -> bool:
return self.apiCaller._send_to_apis("POST", "/jobs")
def reload(self) -> bool:
return self.apiCaller._send_to_apis("POST", "/reload")
def start(self) -> bool:
return self.apiCaller._send_to_apis("POST", "/start")
def stop(self) -> bool:
return self.apiCaller._send_to_apis("POST", "/stop")
def restart(self) -> bool:
return self.apiCaller._send_to_apis("POST", "/restart")
class Instances:
def __init__(self, docker_client):
self.__docker = docker_client
def __instance_from_id(self, _id) -> Instance:
instances: list[Instance] = self.get_instances()
for instance in instances:
if instance._id == _id:
return instance
raise Exception(f"Can't find instance with id {_id}")
def get_instances(self) -> list[Instance]:
instances = []
# Docker instances (containers or services)
if self.__docker is not None:
for instance in self.__docker.containers.list(
all=True, filters={"label": "bunkerweb.UI"}
):
env_variables = {
x[0]: x[1]
for x in [env.split("=") for env in instance.attrs["Config"]["Env"]]
}
apiCaller = ApiCaller()
apiCaller._set_apis(
[
API(
f"http://{instance.name}:{env_variables.get('API_HTTP_PORT', '5000')}",
env_variables.get("API_SERVER_NAME", "bwapi"),
)
]
)
instances.append(
Instance(
instance.id,
instance.name,
instance.name,
"container",
"up" if instance.status == "running" else "down",
instance,
apiCaller,
)
)
instances = sorted(
instances,
key=lambda x: x.name,
)
# Local instance
if os.path.exists("/usr/sbin/nginx"):
instances.insert(
0,
Instance(
"local",
"local",
"127.0.0.1",
"local",
"up" if os.path.exists("/opt/bunkerweb/tmp/nginx.pid") else "down",
),
)
return instances
def reload_instances(self) -> list[str]:
not_reloaded: list[str] = []
for instance in self.get_instances():
if instance.health is False:
not_reloaded.append(instance.name)
continue
if self.reload_instance(None, instance).startswith("Can't reload"):
not_reloaded.append(instance.name)
return not_reloaded
def reload_instance(self, id: int = None, instance: Instance = None) -> str:
if instance is None:
instance = self.__instance_from_id(id)
result = True
if instance._type == "local":
result = (
run(
["sudo", "systemctl", "restart", "bunkerweb"], capture_output=True
).returncode
!= 0
)
elif instance._type == "container":
result = instance.run_jobs()
result = result & instance.reload()
if result:
return f"Instance {instance.name} has been reloaded."
return f"Can't reload {instance.name}"
def start_instance(self, id) -> str:
instance = self.__instance_from_id(id)
result = True
if instance._type == "local":
proc = run(
["sudo", "/opt/bunkerweb/ui/linux.sh", "start"],
capture_output=True,
)
result = proc.returncode == 0
elif instance._type == "container":
result = instance.start()
if result:
return f"Instance {instance.name} has been started."
return f"Can't start {instance.name}"
def stop_instance(self, id) -> str:
instance = self.__instance_from_id(id)
result = True
if instance._type == "local":
proc = run(
["sudo", "/opt/bunkerweb/ui/linux.sh", "stop"],
capture_output=True,
)
result = proc.returncode == 0
elif instance._type == "container":
result = instance.stop()
if result:
return f"Instance {instance.name} has been stopped."
return f"Can't stop {instance.name}"
def restart_instance(self, id) -> str:
instance = self.__instance_from_id(id)
result = True
if instance._type == "local":
proc = run(
["sudo", "/opt/bunkerweb/ui/linux.sh", "restart"],
capture_output=True,
)
result = proc.returncode == 0
elif instance._type == "container":
result = instance.restart()
if result:
return f"Instance {instance.name} has been restarted."
return f"Can't restart {instance.name}"