Proven working Postgresql monitor
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import importlib.util
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class RegistryError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class Plugin:
|
||||
def __init__(self, plugin_root, name):
|
||||
self.name = name
|
||||
self.path = Path(plugin_root) / name
|
||||
self.manifest_path = self.path / "manifest.json"
|
||||
|
||||
if not self.manifest_path.is_file():
|
||||
raise RegistryError(
|
||||
f"plugin manifest not found: {self.manifest_path}"
|
||||
)
|
||||
|
||||
with self.manifest_path.open("r", encoding="utf-8") as f:
|
||||
self.manifest = json.load(f)
|
||||
|
||||
module_name = self.manifest.get("module", "plugin.py")
|
||||
module_path = self.path / module_name
|
||||
|
||||
if not module_path.is_file():
|
||||
raise RegistryError(
|
||||
f"plugin module not found: {module_path}"
|
||||
)
|
||||
|
||||
spec = importlib.util.spec_from_file_location(
|
||||
f"managed_containerd_plugin_{name}",
|
||||
module_path,
|
||||
)
|
||||
|
||||
if spec is None or spec.loader is None:
|
||||
raise RegistryError(
|
||||
f"unable to load plugin: {name}"
|
||||
)
|
||||
|
||||
self.module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(self.module)
|
||||
|
||||
@property
|
||||
def actions(self):
|
||||
return list(self.manifest.get("actions", []))
|
||||
|
||||
@property
|
||||
def required_config(self):
|
||||
return list(
|
||||
self.manifest.get("required_config", [])
|
||||
)
|
||||
|
||||
def validate_config(self, config):
|
||||
missing = [
|
||||
key
|
||||
for key in self.required_config
|
||||
if not config.get(key)
|
||||
]
|
||||
|
||||
if missing:
|
||||
raise RegistryError(
|
||||
"missing required configuration: "
|
||||
+ ", ".join(missing)
|
||||
)
|
||||
|
||||
def execute(self, action, config):
|
||||
if action not in self.actions:
|
||||
raise RegistryError(
|
||||
f"plugin {self.name} does not support action {action}"
|
||||
)
|
||||
|
||||
handler = getattr(self.module, action, None)
|
||||
|
||||
if handler is None:
|
||||
raise RegistryError(
|
||||
f"plugin {self.name} advertises {action} "
|
||||
"but does not implement it"
|
||||
)
|
||||
|
||||
return handler(config)
|
||||
|
||||
|
||||
class Resource:
|
||||
def __init__(self, resource_id, plugin, config):
|
||||
self.resource_id = resource_id
|
||||
self.plugin = plugin
|
||||
self.config = config
|
||||
|
||||
self.plugin.validate_config(config)
|
||||
|
||||
def describe(self):
|
||||
return {
|
||||
"resource": self.resource_id,
|
||||
"plugin": self.plugin.name,
|
||||
"plugin_version": self.plugin.manifest.get(
|
||||
"version"
|
||||
),
|
||||
"actions": self.plugin.actions,
|
||||
"configured": True,
|
||||
}
|
||||
|
||||
|
||||
class Registry:
|
||||
def __init__(self):
|
||||
self.plugin_root = os.environ.get(
|
||||
"MANAGED_CONTAINERD_PLUGIN_ROOT",
|
||||
"/opt/managed-containerd/plugins",
|
||||
)
|
||||
|
||||
self.resources = {}
|
||||
self._load_environment_resource()
|
||||
|
||||
def _load_environment_resource(self):
|
||||
resource_id = os.environ.get("RESOURCE_ID")
|
||||
plugin_name = os.environ.get("PLUGIN")
|
||||
|
||||
if not resource_id:
|
||||
raise RegistryError(
|
||||
"RESOURCE_ID is not configured"
|
||||
)
|
||||
|
||||
if not plugin_name:
|
||||
raise RegistryError(
|
||||
"PLUGIN is not configured"
|
||||
)
|
||||
|
||||
plugin = Plugin(
|
||||
self.plugin_root,
|
||||
plugin_name,
|
||||
)
|
||||
|
||||
config = {
|
||||
key: os.environ.get(key)
|
||||
for key in plugin.required_config
|
||||
}
|
||||
|
||||
self.resources[resource_id] = Resource(
|
||||
resource_id,
|
||||
plugin,
|
||||
config,
|
||||
)
|
||||
|
||||
def list_resources(self):
|
||||
return {
|
||||
resource_id: resource.describe()
|
||||
for resource_id, resource
|
||||
in self.resources.items()
|
||||
}
|
||||
|
||||
def execute(self, resource_id, action):
|
||||
resource = self.resources.get(resource_id)
|
||||
|
||||
if resource is None:
|
||||
raise RegistryError(
|
||||
f"unknown resource: {resource_id}"
|
||||
)
|
||||
|
||||
result = resource.plugin.execute(
|
||||
action,
|
||||
resource.config,
|
||||
)
|
||||
|
||||
return {
|
||||
"ok": True,
|
||||
"resource": resource_id,
|
||||
"plugin": resource.plugin.name,
|
||||
"action": action,
|
||||
"result": result,
|
||||
}
|
||||
Reference in New Issue
Block a user