adding documentation to config service base class
This commit is contained in:
parent
22ff48182a
commit
80073dd8c8
1 changed files with 121 additions and 0 deletions
|
@ -28,6 +28,10 @@ class ConfigServiceBootError(Exception):
|
|||
|
||||
|
||||
class ConfigService(abc.ABC):
|
||||
"""
|
||||
Base class for creating configurable services.
|
||||
"""
|
||||
|
||||
# validation period in seconds, how frequent validation is attempted
|
||||
validation_period = 0.5
|
||||
|
||||
|
@ -35,6 +39,11 @@ class ConfigService(abc.ABC):
|
|||
validation_timer = 5
|
||||
|
||||
def __init__(self, node: CoreNode) -> None:
|
||||
"""
|
||||
Create ConfigService instance.
|
||||
|
||||
:param node: node this service is assigned to
|
||||
"""
|
||||
self.node = node
|
||||
class_file = inspect.getfile(self.__class__)
|
||||
templates_path = pathlib.Path(class_file).parent.joinpath(TEMPLATES_DIR)
|
||||
|
@ -47,6 +56,13 @@ class ConfigService(abc.ABC):
|
|||
|
||||
@staticmethod
|
||||
def clean_text(text: str) -> str:
|
||||
"""
|
||||
Returns space stripped text for string literals, while keeping space
|
||||
indentations.
|
||||
|
||||
:param text: text to clean
|
||||
:return: cleaned text
|
||||
"""
|
||||
return inspect.cleandoc(text)
|
||||
|
||||
@property
|
||||
|
@ -110,6 +126,13 @@ class ConfigService(abc.ABC):
|
|||
raise NotImplementedError
|
||||
|
||||
def start(self) -> None:
|
||||
"""
|
||||
Creates services files/directories, runs startup, and validates based on
|
||||
validation mode.
|
||||
|
||||
:return: nothing
|
||||
:raises ConfigServiceBootError: when there is an error starting service
|
||||
"""
|
||||
logging.info("node(%s) service(%s) starting...", self.node.name, self.name)
|
||||
self.create_dirs()
|
||||
self.create_files()
|
||||
|
@ -122,6 +145,11 @@ class ConfigService(abc.ABC):
|
|||
self.run_validation()
|
||||
|
||||
def stop(self) -> None:
|
||||
"""
|
||||
Stop service using shutdown commands.
|
||||
|
||||
:return: nothing
|
||||
"""
|
||||
for cmd in self.shutdown:
|
||||
try:
|
||||
self.node.cmd(cmd)
|
||||
|
@ -132,10 +160,21 @@ class ConfigService(abc.ABC):
|
|||
)
|
||||
|
||||
def restart(self) -> None:
|
||||
"""
|
||||
Restarts service by running stop and then start.
|
||||
|
||||
:return: nothing
|
||||
"""
|
||||
self.stop()
|
||||
self.start()
|
||||
|
||||
def create_dirs(self) -> None:
|
||||
"""
|
||||
Creates directories for service.
|
||||
|
||||
:return: nothing
|
||||
:raises CoreError: when there is a failure creating a directory
|
||||
"""
|
||||
for directory in self.directories:
|
||||
try:
|
||||
self.node.privatedir(directory)
|
||||
|
@ -146,15 +185,39 @@ class ConfigService(abc.ABC):
|
|||
)
|
||||
|
||||
def data(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Returns key/value data, used when rendering file templates.
|
||||
|
||||
:return: key/value template data
|
||||
"""
|
||||
return {}
|
||||
|
||||
def set_template(self, name: str, template: str) -> None:
|
||||
"""
|
||||
Store custom template to render for a given file.
|
||||
|
||||
:param name: file to store custom template for
|
||||
:param template: custom template to render
|
||||
:return: nothing
|
||||
"""
|
||||
self.custom_templates[name] = template
|
||||
|
||||
def get_text_template(self, name: str) -> str:
|
||||
"""
|
||||
Retrieves text based template for files that do not have a file based template.
|
||||
|
||||
:param name: name of file to get template for
|
||||
:return: template to render
|
||||
"""
|
||||
raise CoreError(f"service({self.name}) unknown template({name})")
|
||||
|
||||
def get_templates(self) -> Dict[str, str]:
|
||||
"""
|
||||
Retrieves mapping of file names to templates for all cases, which
|
||||
includes custom templates, file templates, and text templates.
|
||||
|
||||
:return: mapping of files to templates
|
||||
"""
|
||||
templates = {}
|
||||
for name in self.files:
|
||||
basename = pathlib.Path(name).name
|
||||
|
@ -170,6 +233,11 @@ class ConfigService(abc.ABC):
|
|||
return templates
|
||||
|
||||
def create_files(self) -> None:
|
||||
"""
|
||||
Creates service files inside associated node.
|
||||
|
||||
:return: nothing
|
||||
"""
|
||||
data = self.data()
|
||||
for name in self.files:
|
||||
basename = pathlib.Path(name).name
|
||||
|
@ -191,6 +259,14 @@ class ConfigService(abc.ABC):
|
|||
self.node.nodefile(name, rendered)
|
||||
|
||||
def run_startup(self, wait: bool) -> None:
|
||||
"""
|
||||
Run startup commands for service on node.
|
||||
|
||||
:param wait: wait successful command exit status when True, ignore status
|
||||
otherwise
|
||||
:return: nothing
|
||||
:raises ConfigServiceBootError: when a command that waits fails
|
||||
"""
|
||||
for cmd in self.startup:
|
||||
try:
|
||||
self.node.cmd(cmd, wait=wait)
|
||||
|
@ -200,6 +276,12 @@ class ConfigService(abc.ABC):
|
|||
)
|
||||
|
||||
def run_validation(self) -> None:
|
||||
"""
|
||||
Runs validation commands for service on node.
|
||||
|
||||
:return: nothing
|
||||
:raises ConfigServiceBootError: if there is a validation failure
|
||||
"""
|
||||
start = time.monotonic()
|
||||
cmds = self.validate[:]
|
||||
index = 0
|
||||
|
@ -222,6 +304,13 @@ class ConfigService(abc.ABC):
|
|||
)
|
||||
|
||||
def _render(self, template: Template, data: Dict[str, Any] = None) -> str:
|
||||
"""
|
||||
Renders template providing all associated data to template.
|
||||
|
||||
:param template: template to render
|
||||
:param data: service specific defined data for template
|
||||
:return: rendered template
|
||||
"""
|
||||
if data is None:
|
||||
data = {}
|
||||
return template.render_unicode(
|
||||
|
@ -229,6 +318,13 @@ class ConfigService(abc.ABC):
|
|||
)
|
||||
|
||||
def render_text(self, text: str, data: Dict[str, Any] = None) -> str:
|
||||
"""
|
||||
Renders text based template providing all associated data to template.
|
||||
|
||||
:param text: text to render
|
||||
:param data: service specific defined data for template
|
||||
:return: rendered template
|
||||
"""
|
||||
text = self.clean_text(text)
|
||||
try:
|
||||
template = Template(text)
|
||||
|
@ -240,6 +336,13 @@ class ConfigService(abc.ABC):
|
|||
)
|
||||
|
||||
def render_template(self, basename: str, data: Dict[str, Any] = None) -> str:
|
||||
"""
|
||||
Renders file based template providing all associated data to template.
|
||||
|
||||
:param basename: base name for file to render
|
||||
:param data: service specific defined data for template
|
||||
:return: rendered template
|
||||
"""
|
||||
try:
|
||||
template = self.templates.get_template(basename)
|
||||
return self._render(template, data)
|
||||
|
@ -250,16 +353,34 @@ class ConfigService(abc.ABC):
|
|||
)
|
||||
|
||||
def _define_config(self, configs: List[Configuration]) -> None:
|
||||
"""
|
||||
Initializes default configuration data.
|
||||
|
||||
:param configs: configs to initialize
|
||||
:return: nothing
|
||||
"""
|
||||
for config in configs:
|
||||
self.config[config.id] = config
|
||||
|
||||
def render_config(self) -> Dict[str, str]:
|
||||
"""
|
||||
Returns configuration data key/value pairs for rendering a template.
|
||||
|
||||
:return: nothing
|
||||
"""
|
||||
if self.custom_config:
|
||||
return self.custom_config
|
||||
else:
|
||||
return {k: v.default for k, v in self.config.items()}
|
||||
|
||||
def set_config(self, data: Dict[str, str]) -> None:
|
||||
"""
|
||||
Set configuration data from key/value pairs.
|
||||
|
||||
:param data: configuration key/values to set
|
||||
:return: nothing
|
||||
:raise CoreError: when an unknown configuration value is given
|
||||
"""
|
||||
for key, value in data.items():
|
||||
if key not in self.config:
|
||||
raise CoreError(f"unknown config: {key}")
|
||||
|
|
Loading…
Add table
Reference in a new issue