core-extra/daemon/core/configservice/base.py

128 lines
3.4 KiB
Python

import abc
import enum
import inspect
import logging
import pathlib
import time
from typing import Any, Dict, List
from mako import exceptions
from mako.lookup import TemplateLookup
from core.errors import CoreCommandError, CoreError
from core.nodes.base import CoreNode
TEMPLATES_DIR = "templates"
class ConfigServiceMode(enum.Enum):
BLOCKING = 0
NON_BLOCKING = 1
TIMER = 2
class ConfigService(abc.ABC):
# validation period in seconds, how frequent validation is attempted
validation_period = 0.5
# time to wait in seconds for determining if service started successfully
validation_timer = 5
def __init__(self, node: CoreNode) -> None:
self.node = node
class_file = inspect.getfile(self.__class__)
templates_path = pathlib.Path(class_file).parent.joinpath(TEMPLATES_DIR)
logging.info(templates_path)
self.templates = TemplateLookup(directories=templates_path)
@property
@abc.abstractmethod
def name(self):
raise NotImplementedError
@property
@abc.abstractmethod
def group(self):
raise NotImplementedError
@property
@abc.abstractmethod
def executables(self) -> List[str]:
raise NotImplementedError
@property
@abc.abstractmethod
def dependencies(self) -> List[str]:
raise NotImplementedError
@property
@abc.abstractmethod
def startup(self) -> List[str]:
raise NotImplementedError
@property
@abc.abstractmethod
def validate(self) -> List[str]:
raise NotImplementedError
@property
@abc.abstractmethod
def shutdown(self) -> List[str]:
raise NotImplementedError
@property
@abc.abstractmethod
def validation_mode(self) -> ConfigServiceMode:
raise NotImplementedError
def start(self) -> None:
if not self.startup:
return
wait = self.validation_mode == ConfigServiceMode.BLOCKING
start = time.monotonic()
index = 0
cmds = self.startup[:]
while cmds:
cmd = cmds[index]
try:
self.node.cmd(cmd, wait=wait)
del cmds[index]
index += 1
except CoreCommandError:
logging.exception("error starting command")
time.sleep(self.validation_period)
if time.monotonic() - start > 0:
raise CoreError(
f"node({self.node.name}) service({self.name()}) failed to start"
)
def stop(self) -> None:
if not self.shutdown:
return
for cmd in self.shutdown:
self.node.cmd(cmd, wait=False)
def restart(self):
self.stop()
self.start()
def run(self, cmd: str, wait: bool = True):
self.node.cmd(cmd, wait)
def create_files(self) -> None:
raise NotImplementedError
def render(self, name: str, data: Dict[str, Any] = None) -> None:
if data is None:
data = {}
try:
template = self.templates.get_template(name)
rendered = template.render_unicode(node=self.node, **data)
print(rendered)
# self.node.nodefile(name, rendered)
except Exception:
raise CoreError(
f"error rendering template: {name}"
f"{exceptions.text_error_template().render()}"
)