🚧 WIP
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
"""mosquitto.conf generator — PostgreSQL model to config text (spec sections 61, 25).
|
||||
|
||||
The generated configuration MUST avoid the options deprecated in
|
||||
Mosquitto 2.1 (password_file, acl_file, per_listener_settings): those are
|
||||
removed in 3.0 (spec section 3.1 note).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.models import BrokerSettings, ListenerConfig
|
||||
|
||||
_BOOL = {True: "true", False: "false"}
|
||||
|
||||
|
||||
@dataclass
|
||||
class GenerationResult:
|
||||
config_text: str
|
||||
warnings: list[str] = field(default_factory=list)
|
||||
|
||||
|
||||
def _global_section(db: Session, warnings: list[str]) -> list[str]:
|
||||
lines: list[str] = []
|
||||
for setting in db.scalars(select(BrokerSettings)).all():
|
||||
key = setting.key.strip()
|
||||
value = setting.value.strip()
|
||||
if not key or key.startswith("#"):
|
||||
continue
|
||||
lines.append(f"{key} {value}")
|
||||
return lines
|
||||
|
||||
|
||||
def _listener_block(listener: ListenerConfig, warnings: list[str]) -> list[str]:
|
||||
lines: list[str] = []
|
||||
if not listener.enabled:
|
||||
return lines
|
||||
lines.append(f"listener {listener.port} {listener.bind_address or ''}".rstrip())
|
||||
if listener.bind_address is None:
|
||||
# `listener <port>` without bind address binds all interfaces.
|
||||
lines[-1] = f"listener {listener.port}"
|
||||
lines.append(f"protocol {listener.protocol}")
|
||||
if listener.allow_anonymous:
|
||||
lines.append("listener_allow_anonymous true")
|
||||
if listener.max_connections != -1:
|
||||
lines.append(f"max_connections {listener.max_connections}")
|
||||
if listener.tls_enabled:
|
||||
# TLS blocks only become valid once PKI ships (Release 2); we
|
||||
# generate them now so the model is forward-compatible, but warn.
|
||||
warnings.append(
|
||||
f"listener '{listener.name}': TLS requested but PKI is not "
|
||||
"available in Release 1; certfile/keyfile not set"
|
||||
)
|
||||
if listener.tls_min_version:
|
||||
lines.append(f"tls_version {listener.tls_min_version}")
|
||||
if listener.require_certificate:
|
||||
lines.append("require_certificate true")
|
||||
if listener.use_identity_as_username:
|
||||
lines.append("use_identity_as_username true")
|
||||
return lines
|
||||
|
||||
|
||||
def generate_config(db: Session) -> GenerationResult:
|
||||
"""Build the complete mosquitto.conf from the database model.
|
||||
|
||||
The platform ALWAYS regenerates the full file; it never edits the
|
||||
active file in place (spec section 61).
|
||||
"""
|
||||
warnings: list[str] = []
|
||||
|
||||
listeners = db.scalars(select(ListenerConfig)).all()
|
||||
enabled = [item for item in listeners if item.enabled]
|
||||
|
||||
lines: list[str] = []
|
||||
lines.append("# Generated by MQTT Management Platform — DO NOT EDIT BY HAND")
|
||||
lines.append("# Ownership: PostgreSQL model -> revision -> this file (spec 61)")
|
||||
lines.append("")
|
||||
|
||||
lines.append("# --- Global settings ---")
|
||||
lines.append("per_listener_settings false")
|
||||
lines.append("allow_anonymous false")
|
||||
global_lines = _global_section(db, warnings)
|
||||
if global_lines:
|
||||
lines.extend(global_lines)
|
||||
lines.append("")
|
||||
|
||||
# Dynamic security plugin: global, so it applies to every listener.
|
||||
lines.append("# --- Dynamic Security ---")
|
||||
lines.append("global_plugin /usr/lib/mosquitto_dynamic_security.so")
|
||||
lines.append("plugin_opt_config_file /mosquitto/config/dynamic-security.json")
|
||||
lines.append("")
|
||||
|
||||
if enabled:
|
||||
lines.append("# --- Listeners ---")
|
||||
for listener in enabled:
|
||||
block = _listener_block(listener, warnings)
|
||||
if block:
|
||||
lines.append(f"# listener: {listener.name}")
|
||||
lines.extend(block)
|
||||
lines.append("")
|
||||
else:
|
||||
warnings.append(
|
||||
"no enabled listeners; broker would fall back to loopback-only "
|
||||
"with anonymous access — refusing to generate"
|
||||
)
|
||||
raise ValueError("no enabled listeners in configuration model")
|
||||
|
||||
lines.append("# --- Persistence ---")
|
||||
lines.append("persistence true")
|
||||
lines.append("persistence_location /mosquitto/data/")
|
||||
lines.append("")
|
||||
|
||||
lines.append("# --- Logging ---")
|
||||
lines.append("log_dest stdout")
|
||||
lines.append("log_timestamp true")
|
||||
lines.append("log_timestamp_format %Y-%m-%dT%H:%M:%S")
|
||||
|
||||
return GenerationResult(config_text="\n".join(lines) + "\n", warnings=warnings)
|
||||
Reference in New Issue
Block a user