fix(qa): health monitor SiteManager, WP plugins, favicon, download ZIPs
- Health monitor now uses SiteManager for complete site discovery - SEO Bridge: GPLv2+ license, Tested up to 6.9, fix escaping - OpenPanel: fix wp_unslash, reduce tags, update branding - Add logo.svg favicon, static file serving, plugin ZIPs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -9,8 +9,7 @@ This module provides comprehensive health monitoring capabilities including:
|
||||
- Dependency health checks
|
||||
- System uptime tracking
|
||||
|
||||
Author: Coolify MCP Team
|
||||
Version: 7.2
|
||||
Author: MCP Hub Team
|
||||
"""
|
||||
|
||||
import json
|
||||
@@ -24,6 +23,7 @@ from typing import Any
|
||||
|
||||
from core.audit_log import AuditLogger
|
||||
from core.project_manager import ProjectManager
|
||||
from core.site_manager import SiteManager
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -133,6 +133,7 @@ class HealthMonitor:
|
||||
audit_logger: AuditLogger | None = None,
|
||||
metrics_retention_hours: int = 24,
|
||||
max_metrics_per_project: int = 1000,
|
||||
site_manager: SiteManager | None = None,
|
||||
):
|
||||
"""
|
||||
Initialize health monitor.
|
||||
@@ -142,8 +143,10 @@ class HealthMonitor:
|
||||
audit_logger: Optional audit logger for logging health events
|
||||
metrics_retention_hours: Hours to retain historical metrics
|
||||
max_metrics_per_project: Maximum metrics to store per project
|
||||
site_manager: Optional SiteManager for comprehensive site discovery
|
||||
"""
|
||||
self.project_manager = project_manager
|
||||
self.site_manager = site_manager
|
||||
self.audit_logger = audit_logger
|
||||
self.metrics_retention_hours = metrics_retention_hours
|
||||
self.max_metrics_per_project = max_metrics_per_project
|
||||
@@ -401,9 +404,17 @@ class HealthMonitor:
|
||||
start_time = time.time()
|
||||
|
||||
try:
|
||||
# Get plugin instance
|
||||
# Get plugin instance from ProjectManager
|
||||
plugin = self.project_manager.projects.get(project_id)
|
||||
if not plugin:
|
||||
|
||||
if plugin:
|
||||
# Perform health check via plugin instance
|
||||
health_result = await plugin.health_check()
|
||||
elif self.site_manager:
|
||||
# Fallback: site exists in SiteManager but not ProjectManager
|
||||
# (e.g. WooCommerce uses CONSUMER_KEY, not USERNAME/APP_PASSWORD)
|
||||
health_result = await self._basic_site_health_check(project_id)
|
||||
else:
|
||||
return ProjectHealthStatus(
|
||||
project_id=project_id,
|
||||
healthy=False,
|
||||
@@ -413,9 +424,6 @@ class HealthMonitor:
|
||||
recent_errors=["Project not found"],
|
||||
alerts=["CRITICAL: Project not found"],
|
||||
)
|
||||
|
||||
# Perform health check
|
||||
health_result = await plugin.health_check()
|
||||
response_time_ms = (time.time() - start_time) * 1000
|
||||
|
||||
# Handle both dict and string (JSON) responses
|
||||
@@ -495,6 +503,43 @@ class HealthMonitor:
|
||||
alerts=[f"CRITICAL: Health check failed - {error_msg}"],
|
||||
)
|
||||
|
||||
async def _basic_site_health_check(self, project_id: str) -> dict[str, Any]:
|
||||
"""Basic HTTP health check for sites not in ProjectManager."""
|
||||
import aiohttp
|
||||
|
||||
if not self.site_manager:
|
||||
return {"healthy": False, "message": "SiteManager not available"}
|
||||
|
||||
# Parse plugin_type and site_id from full_id (e.g. "woocommerce_site1")
|
||||
parts = project_id.split("_", 1)
|
||||
if len(parts) < 2:
|
||||
return {"healthy": False, "message": f"Invalid project_id format: {project_id}"}
|
||||
|
||||
plugin_type = parts[0]
|
||||
site_id = parts[1]
|
||||
|
||||
try:
|
||||
config = self.site_manager.get_site_config(plugin_type, site_id)
|
||||
except (KeyError, ValueError):
|
||||
return {"healthy": False, "message": f"Site not found: {project_id}"}
|
||||
|
||||
url = config.url
|
||||
if not url:
|
||||
return {"healthy": False, "message": "No URL configured for site"}
|
||||
|
||||
try:
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(
|
||||
url, timeout=aiohttp.ClientTimeout(total=10), ssl=False
|
||||
) as resp:
|
||||
return {
|
||||
"healthy": resp.status < 500,
|
||||
"status_code": resp.status,
|
||||
"message": f"HTTP {resp.status} from {url}",
|
||||
}
|
||||
except Exception as e:
|
||||
return {"healthy": False, "message": f"Connection failed: {e}"}
|
||||
|
||||
async def check_all_projects_health(self, include_metrics: bool = True) -> dict[str, Any]:
|
||||
"""
|
||||
Check health of all projects.
|
||||
@@ -507,8 +552,14 @@ class HealthMonitor:
|
||||
"""
|
||||
health_statuses = {}
|
||||
|
||||
# Collect all known project/site IDs from both sources
|
||||
all_project_ids = set(self.project_manager.projects.keys())
|
||||
if self.site_manager:
|
||||
for site_info in self.site_manager.list_all_sites():
|
||||
all_project_ids.add(site_info["full_id"])
|
||||
|
||||
# Check each project
|
||||
for project_id in self.project_manager.projects.keys():
|
||||
for project_id in sorted(all_project_ids):
|
||||
status = await self.check_project_health(project_id, include_metrics)
|
||||
health_statuses[project_id] = status.to_dict()
|
||||
|
||||
@@ -673,7 +724,10 @@ def get_health_monitor() -> HealthMonitor | None:
|
||||
|
||||
|
||||
def initialize_health_monitor(
|
||||
project_manager: ProjectManager, audit_logger: AuditLogger | None = None, **kwargs
|
||||
project_manager: ProjectManager,
|
||||
audit_logger: AuditLogger | None = None,
|
||||
site_manager: SiteManager | None = None,
|
||||
**kwargs,
|
||||
) -> HealthMonitor:
|
||||
"""
|
||||
Initialize the global health monitor.
|
||||
@@ -681,11 +735,14 @@ def initialize_health_monitor(
|
||||
Args:
|
||||
project_manager: Project manager instance
|
||||
audit_logger: Optional audit logger
|
||||
site_manager: Optional SiteManager for comprehensive site discovery
|
||||
**kwargs: Additional configuration options
|
||||
|
||||
Returns:
|
||||
HealthMonitor instance
|
||||
"""
|
||||
global _health_monitor
|
||||
_health_monitor = HealthMonitor(project_manager, audit_logger, **kwargs)
|
||||
_health_monitor = HealthMonitor(
|
||||
project_manager, audit_logger, site_manager=site_manager, **kwargs
|
||||
)
|
||||
return _health_monitor
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}MCP Hub{% endblock %}</title>
|
||||
<link rel="icon" type="image/svg+xml" href="/static/logo.svg">
|
||||
|
||||
<!-- Tailwind CSS from CDN -->
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}{{ t.dashboard }}{% endblock %} - MCP Hub</title>
|
||||
<link rel="icon" type="image/svg+xml" href="/static/logo.svg">
|
||||
|
||||
<!-- Vazirmatn Font for Persian -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{ t.login_title }} - MCP Hub</title>
|
||||
<link rel="icon" type="image/svg+xml" href="/static/logo.svg">
|
||||
|
||||
<!-- Tailwind CSS -->
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
|
||||
1
core/templates/static/logo.svg
Normal file
1
core/templates/static/logo.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1024" height="1024"><style>.a{fill:#51b9f4}.b{fill:#fec13d}</style><path class="a" d="m496.4 11.5q5.4-0.4 10.9-0.5 5.4-0.1 10.9 0.1 5.4 0.2 10.8 0.7 5.5 0.4 10.9 1.2c56.2 7.7 99.4 36 133.3 81.3 31 41.4 41 94.3 34.8 144.5-6.9 54.7-31.6 89.2-71.8 124.8-9.7 8.6-19.4 21-29.9 28.7 8 7.2 17.5 17 25.1 24.8 8.6-11.9 22.8-24.8 33.4-35.4 10.6-10.1 20.7-22.2 32.2-31.2 44.5-34.8 109.1-43.7 163.2-31.3 97.6 22.4 162.8 115.9 151.4 215.3-12.8 111.6-114.9 189.3-225.7 173.7-56.9-8-89.1-29.9-126.7-72.5-8.4-9.5-20.3-19-28.1-29.2-3 4.4-20.1 21-24.7 25.2q0.8 0.7 1.6 1.4c10.3 8.9 20.5 20.3 30 29.2 31.4 29.2 55.6 55.7 65.1 98.8 3 13.7 4.9 22.1 6.1 36.6 4.1 52.5-11.2 105-46 144.9-28.1 32.3-64.1 56.5-106.4 64.9-9.6 2-17.3 3.9-27.3 4.6-11.3 1.4-27.3 0.9-38.7-0.3-55.1-6.2-100.6-31.3-135.2-74.7-6.8-8.5-12.8-17.6-18.1-27.2-5.2-9.5-9.7-19.4-13.3-29.7-3.6-10.3-6.3-20.8-8.1-31.6-1.9-10.7-2.8-21.5-2.8-32.4-0.3-41.9 11.1-88.4 38.8-121 5-5.8 10.5-11.8 16.2-17.1 15.8-14.8 31.2-33.3 48-46.7-7.7-8-17.1-16.5-24.2-24.6-8.4 9.8-18.5 19-27.4 28.3-10.5 10.8-20.7 21.7-31.8 31.9-36.3 32.8-85.8 44.5-133.6 42.7-12.8-0.5-25.5-2.3-38-5.3-12.5-3-24.6-7.3-36.2-12.7-11.7-5.4-22.7-11.9-33.1-19.4-10.3-7.6-19.9-16.2-28.6-25.6-46.8-50.7-62.6-116.6-46.9-183.1 8.7-41.1 30.3-72.1 60.7-100.4 64.9-60.6 180.9-67.1 250.4-10.7 10.9 8.8 22.5 21.5 32.4 31.7 10.5 10.9 21.9 21.7 32.1 33 8.1-11 14.4-15.9 23.9-24.9-37.7-41.9-77.8-63.2-94-122.1-17.9-65.2-8.7-131.9 34.5-185.2 37.9-46.8 81.1-66.8 139.9-73.5zm-44.5 380.8q-5.1 5.1-10.1 10.1-5.1 5-10.2 10.1-5 5-10.1 10.1-5 5-10 10.1c-3.7 3.7-16.3 16.8-20.1 19.1-12.9-14.3-28.9-27.9-41.3-41.9-35.7-40-68.4-67.4-124.3-70.7-53.9-3.2-94.4 9.6-135 46-8.2 7.5-15.6 15.7-22.2 24.7-6.6 8.9-12.3 18.5-16.9 28.5-4.7 10.1-8.4 20.6-11.1 31.4-2.6 10.7-4.2 21.7-4.6 32.8-6.6 133.7 129.3 221.3 249 166.3 3.7-2.1 7.3-4.3 10.8-6.5 10.9-6.8 20.8-15.5 30.3-24.1 8.2-7.5 14.8-16.4 22.4-24.5 13.8-14.7 29-28.3 43.3-42.4 4.5 5.4 11.9 12.5 17.1 17.6l28.4 28.4c3.5 3.5 11.1 10.7 14.1 14.3-7.4 9.1-18.4 18.4-26.7 27.1-18.8 19.6-40.3 36.2-56.9 57.9-24.9 32.5-31.7 75.7-28.5 115.7 4 47.7 27.3 87 63.8 117.4 6.4 5.3 13.3 10.2 20.5 14.5 7.2 4.3 14.8 8 22.5 11.2 7.8 3.2 15.8 5.8 23.9 7.8 8.2 2 16.5 3.4 24.8 4.2 7.8 0.6 17.8 0.5 25.6 0.3 35.2-1.1 68.9-14.1 95.9-36.2 8.1-6.7 12.7-9.6 20.1-17.7 33.7-36.9 49.6-74.3 48.1-124.8-1.2-38-9.3-69-34.2-98.8-10.3-12.4-23-23.8-34.6-34.8-14.7-14-29.1-29.5-43.8-43.4l-0.3-0.3c5.7-7.1 11.7-13.2 18.2-19.6 13.7-13.5 26.9-27.5 41.1-40.5l0.6 0.6c9.5 7.9 18.7 19.1 27.8 27.7 18.6 17.9 34.5 38.1 54.9 54.1 33.2 26.3 76.5 33.7 117.8 30.3 52.5-4.3 98.3-36.2 127.8-78.8 18.8-27.3 28.5-62 27.5-95.2-0.2-5 0-9.8-0.4-14.8-1-11.4-3.1-22.6-6.3-33.5-3.2-10.9-7.6-21.5-12.9-31.6-5.4-10-11.7-19.5-19-28.3-7.2-8.8-15.4-16.8-24.2-24-40.2-32.9-81.7-43.3-132.6-38.3-50.9 4.9-82 28.5-114.5 65.8-6.4 7.3-15 14.7-21.6 22-5.5 5.4-19.7 20.8-25 24.3-19.2-20.2-40.1-39.5-59.3-59.7 12.5-15 27.9-29.5 41.9-43.3 5.9-5.8 13.8-11.6 20.3-18.1 32.1-32.4 48.9-63.7 50.5-110 0.4-10.8 0.6-19.1-0.4-30.1-1.1-11.2-3.3-22.3-6.6-33.1-3.3-10.7-7.6-21.2-13-31.1-5.3-9.9-11.7-19.3-18.9-27.9-7.2-8.7-15.3-16.6-24-23.7-29.7-24.3-61.1-36.9-99.7-39-4.5-0.2-14.1-0.4-18.5 0.1-49.6 3.5-86.3 20.5-120.3 57.4-33.6 36.6-46.8 80.9-43.8 130 2.7 45.3 18.5 77.4 51.2 108.8 20 19.3 42.8 39.8 61.7 60z"/><path class="b" d="m210.1 432.1c43.8 0.6 78.9 36.4 78.7 80.1-0.3 43.8-35.9 79.2-79.6 79.2-44.3 0-80-35.9-79.8-80.1 0.3-44.2 36.5-79.8 80.7-79.2zm1.1 134.1c30-1.2 53.3-26.3 52.3-56.3-1-29.9-26-53.4-55.9-52.6-30.3 0.8-54.1 26-53.1 56.3 1 30.2 26.5 53.9 56.7 52.6z"/><path class="b" d="m503.9 129.7c43.8-4.5 82.9 27.4 87.3 71.2 4.4 43.8-27.5 82.9-71.3 87.3-43.8 4.3-82.8-27.6-87.2-71.3-4.4-43.8 27.5-82.8 71.2-87.2zm12.9 133.5c29.9-2.7 52-29.1 49.4-59.1-2.7-30-29.1-52.1-59.1-49.5-30 2.6-52.3 29.1-49.6 59.1 2.7 30.1 29.2 52.3 59.3 49.5z"/><path class="b" d="m503.3 735.5c43.8-4.8 83.1 26.9 87.9 70.7 4.7 43.7-27 83-70.8 87.7-43.7 4.6-82.9-27-87.6-70.7-4.7-43.7 26.9-82.9 70.5-87.7zm12.5 133.5c29.9-2.1 52.5-28 50.5-58-2-30-27.8-52.7-57.8-50.8-30.2 1.8-53.1 27.9-51.1 58 2 30.2 28.2 53 58.4 50.8z"/><path class="b" d="m805.8 432.7c43.7-5 83.3 26.4 88.2 70.2 4.9 43.7-26.6 83.2-70.3 88-43.7 4.9-83-26.5-87.9-70.2-5-43.6 26.4-83 70-88zm11.6 133.6c29.9-1.5 53-26.9 51.8-56.8-1.3-30-26.5-53.3-56.4-52.2-30.3 1-53.9 26.5-52.7 56.8 1.3 30.3 27 53.7 57.3 52.2z"/><path class="a" d="m511 451.9c3.1 0.9 33.1 32.8 37.8 36.9 2.7 2.4 19.9 19.4 22.3 22.7-2.6 4.7-53.2 55.7-59.3 60.2-0.2 0-0.4 0-0.5-0.1-2.1-0.8-56.2-54.4-59.3-59.3 1.4-4.2 52.5-54.7 59-60.4zm-24.9 59.5c3.3 4.6 19.8 20.5 24.8 25.4 0.5 0 1 0.1 1.4 0 8-8.8 16-16.6 24.6-24.8-3-3-24.1-24.6-25.8-25.3-3.7 4.3-21 21.9-25 24.7z"/></svg>
|
||||
|
After Width: | Height: | Size: 4.6 KiB |
Reference in New Issue
Block a user