Add Asterisk configuration and diagnostics support

- Updated .env.example to include Asterisk templates path.
- Modified docker-compose.yml to mount the templates directory.
- Enhanced backend Dockerfile to copy templates into the container.
- Introduced Asterisk diagnostics functionality in asterisk_profiles.py, allowing for baseline checks and diagnostics reporting.
- Integrated Asterisk diagnostics into the device diagnostics workflow in graph.py.
- Added formatting for Asterisk baseline drift reports in diagnostic_format.py.
- Updated SKILL.md to document new config baseline drift feature for Asterisk.

This commit enhances the system's capabilities for managing Asterisk configurations and diagnostics, improving overall troubleshooting processes.
This commit is contained in:
2026-06-15 07:49:10 +03:00
parent 0375b20bb4
commit 9fc35e86fe
13 changed files with 773 additions and 4 deletions

View File

@@ -0,0 +1,138 @@
"""Tests for Asterisk golden config baseline."""
from __future__ import annotations
import json
import os
from pathlib import Path
os.environ.setdefault("SECRET_KEY", "test-secret-key-for-unit-tests-only")
_test_dir = Path(__file__).resolve().parent
_repo_root = _test_dir.parent.parent
_templates_root = _repo_root / "templates" / "asterisk"
if not _templates_root.is_dir():
_templates_root = _test_dir.parent / "templates" / "asterisk"
os.environ["ASTERISK_TEMPLATES_PATH"] = str(_templates_root)
from app.services.asterisk_baseline import ( # noqa: E402
compare_against_baseline,
compare_file,
invalidate_manifest_cache,
profile_for_catalog,
resolve_variables,
substitute,
)
from app.services.diagnostic_format import format_tool_output_markdown # noqa: E402
def test_profile_for_geneseasx_catalog():
invalidate_manifest_cache()
assert profile_for_catalog("asterisk_geneseasx") == "geneseasx"
assert profile_for_catalog("asterisk") == "geneseasx"
assert profile_for_catalog("asterisk_satbox") is None
def test_substitute_variables():
assert substitute("local_net={{PHONE_SUBNET}}", {"PHONE_SUBNET": "192.168.0.0/24"}) == (
"local_net=192.168.0.0/24"
)
def test_compare_file_detects_missing_line():
live = """
[transport-udp]
type=transport
local_net=10.20.30.0/24
external_media_address=10.20.30.222
"""
spec = {
"path": "pjsip.conf",
"description": "test",
"required_lines": [
"local_net={{PHONE_SUBNET}}",
"local_net={{VOIP_SUBNET}}",
],
}
variables = {"PHONE_SUBNET": "192.168.0.0/24", "VOIP_SUBNET": "10.20.30.0/24"}
result = compare_file(live, spec, variables)
assert result.ok is False
assert any(not c.ok for c in result.checks)
def test_compare_file_passes_golden_pjsip():
live = """
[transport-udp]
type=transport
protocol=udp
local_net=192.168.0.0/24
local_net=10.20.30.0/24
external_media_address=10.20.30.222
external_signaling_address=10.20.30.222
"""
spec = {
"path": "pjsip.conf",
"required_lines": [
"local_net={{PHONE_SUBNET}}",
"local_net={{VOIP_SUBNET}}",
"external_media_address={{ASTERISK_IP}}",
"external_signaling_address={{ASTERISK_IP}}",
],
}
variables = {
"PHONE_SUBNET": "192.168.0.0/24",
"VOIP_SUBNET": "10.20.30.0/24",
"ASTERISK_IP": "10.20.30.222",
}
result = compare_file(live, spec, variables)
assert result.ok is True
def test_compare_against_baseline_full_report():
invalidate_manifest_cache()
live_files = {
"pjsip.conf": """
local_net=192.168.0.0/24
local_net=10.20.30.0/24
external_media_address=10.20.30.222
external_signaling_address=10.20.30.222
""",
"rtp.conf": "rtpstart=10000\nrtpend=10029\n",
"extensions.conf": "[public]\nexten => _7XXXX,1,NoOp(trunk)\n",
}
report = compare_against_baseline(live_files, profile="geneseasx")
assert report is not None
assert report.ok is True
assert "6/6" in report.summary or "checks passed" in report.summary
def test_env_override_variables(monkeypatch):
invalidate_manifest_cache()
from app.services.asterisk_baseline import load_manifest
manifest = load_manifest("geneseasx", force=True)
monkeypatch.setenv("ASTERISK_BASELINE_ASTERISK_IP", "10.99.99.99")
vars = resolve_variables(manifest or {}, {})
assert vars["ASTERISK_IP"] == "10.99.99.99"
def test_baseline_markdown_formatting():
payload = {
"profile": "geneseasx",
"summary": "Config baseline: 5/6 checks passed",
"variables": {"ASTERISK_IP": "10.20.30.222"},
"files": [
{
"path": "pjsip.conf",
"missing": False,
"checks": [
{
"kind": "required_line",
"expected": "local_net=192.168.0.0/24",
"ok": False,
}
],
}
],
}
md = format_tool_output_markdown("asterisk_config_baseline", json.dumps(payload))
assert "DRIFT" in md
assert "pjsip.conf" in md