Proven working Postgresql monitor

This commit is contained in:
Lyncoln
2026-09-17 09:23:17 -04:00
commit 0123da0e12
7 changed files with 769 additions and 0 deletions
+174
View File
@@ -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,
}
+165
View File
@@ -0,0 +1,165 @@
#!/usr/bin/env python3
import json
import os
import signal
import socket
import traceback
from registry import Registry, RegistryError
SOCKET_PATH = os.environ.get(
"MANAGED_CONTAINERD_SOCKET",
"/run/managed-containerd/managed-containerd.sock",
)
server_socket = None
registry = None
def handle_request(req):
action = req.get("action")
if action == "ping":
return {
"ok": True,
"daemon": "managed-containerd",
"protocol_version": 1,
}
if action == "registry.list":
return {
"ok": True,
"resources": registry.list_resources(),
}
resource = req.get("resource")
if not resource:
return {
"ok": False,
"error": "resource is required",
}
return registry.execute(
resource,
action,
)
def cleanup_socket():
try:
os.unlink(SOCKET_PATH)
except FileNotFoundError:
pass
def shutdown(signum, frame):
global server_socket
print(
f"managed-containerd received signal {signum}; shutting down",
flush=True,
)
if server_socket is not None:
try:
server_socket.close()
except OSError:
pass
cleanup_socket()
raise SystemExit(0)
def serve():
global server_socket
global registry
registry = Registry()
os.makedirs(
os.path.dirname(SOCKET_PATH),
exist_ok=True,
)
cleanup_socket()
signal.signal(signal.SIGTERM, shutdown)
signal.signal(signal.SIGINT, shutdown)
server_socket = socket.socket(
socket.AF_UNIX,
socket.SOCK_STREAM,
)
server_socket.bind(SOCKET_PATH)
os.chmod(SOCKET_PATH, 0o660)
server_socket.listen(16)
print(
f"managed-containerd listening on {SOCKET_PATH}",
flush=True,
)
print(
"registered resources: "
+ ", ".join(registry.resources),
flush=True,
)
try:
while True:
conn, _ = server_socket.accept()
with conn:
try:
raw = b""
while b"\n" not in raw:
chunk = conn.recv(65536)
if not chunk:
break
raw += chunk
req = json.loads(
raw.decode("utf-8").strip()
)
response = handle_request(req)
except (
RegistryError,
ValueError,
KeyError,
) as exc:
response = {
"ok": False,
"error": str(exc),
}
except Exception as exc:
traceback.print_exc()
response = {
"ok": False,
"error": str(exc),
}
conn.sendall(
json.dumps(
response,
default=str,
).encode("utf-8")
+ b"\n"
)
finally:
cleanup_socket()
if __name__ == "__main__":
serve()