Publish curated Unraid-AppOps-Gateway source from ba66029223865607deddc234e283c11127324eb8
This commit is contained in:
1 parent
820244dbb3
commit
8dd4b40252
52 files changed
+11814
-288
No files matched your search
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
@@ -136,6 +137,200 @@ class PortainerConnector(BaseConnector):
|
||||
|
||||
return {'status': 'ok', 'containers': containers}
|
||||
|
||||
def forge_route_network_readiness(self) -> dict[str, Any]:
|
||||
"""Check only the fixed NPM and Forge frontdoor network membership."""
|
||||
try:
|
||||
config = self._config()
|
||||
except Exception: # noqa: BLE001 - fixed projection never returns config diagnostics.
|
||||
config = None
|
||||
try:
|
||||
parsed_url = urlsplit(config.url) if config else None
|
||||
parsed_port = parsed_url.port if parsed_url else None
|
||||
base_url = _safe_portainer_base_url(config.url) if config else None
|
||||
except (TypeError, ValueError):
|
||||
parsed_url = None
|
||||
parsed_port = None
|
||||
base_url = None
|
||||
if (
|
||||
not config
|
||||
or not isinstance(config.url, str)
|
||||
or len(config.url) > 2048
|
||||
or config.url != config.url.strip()
|
||||
or any(char.isspace() or ord(char) < 32 or ord(char) == 127 for char in config.url)
|
||||
or "\\" in config.url
|
||||
or "?" in config.url
|
||||
or "#" in config.url
|
||||
or settings.apis.get('PORTAINER_VERIFY_TLS', settings.verify_tls) is not True
|
||||
or config.verify_tls is not True
|
||||
or parsed_url is None
|
||||
or parsed_url.scheme != 'https'
|
||||
or not parsed_url.hostname
|
||||
or (parsed_port is not None and not 1 <= parsed_port <= 65535)
|
||||
or parsed_url.username is not None
|
||||
or parsed_url.password is not None
|
||||
or parsed_url.query
|
||||
or parsed_url.fragment
|
||||
or '@' in parsed_url.netloc
|
||||
or '%' in parsed_url.netloc
|
||||
or any(segment in {".", ".."} for segment in parsed_url.path.split("/"))
|
||||
or base_url != config.url
|
||||
or not isinstance(config.api_key, str)
|
||||
or not config.api_key
|
||||
or re.fullmatch(r'[1-9][0-9]{0,9}', config.endpoint_id) is None
|
||||
):
|
||||
return {
|
||||
'status': 'unknown',
|
||||
'network': 'itworx-mcp-hub-npm',
|
||||
'npmAttached': None,
|
||||
'frontdoorAttached': None,
|
||||
}
|
||||
try:
|
||||
with httpx.Client(
|
||||
timeout=_PORTAINER_DEFAULT_TIMEOUT_SECONDS,
|
||||
verify=True,
|
||||
follow_redirects=False,
|
||||
) as client:
|
||||
response = client.get(
|
||||
f'{config.url}/api/endpoints/{config.endpoint_id}/docker/containers/json?all=1',
|
||||
headers={'Accept': 'application/json', 'X-API-Key': config.api_key},
|
||||
follow_redirects=False,
|
||||
)
|
||||
if type(getattr(response, 'status_code', None)) is not int or response.status_code != 200:
|
||||
return {
|
||||
'status': 'unknown',
|
||||
'network': 'itworx-mcp-hub-npm',
|
||||
'npmAttached': None,
|
||||
'frontdoorAttached': None,
|
||||
}
|
||||
payload = response.json()
|
||||
except Exception: # noqa: BLE001 - never expose a Docker/API credential or response.
|
||||
return {
|
||||
'status': 'unknown',
|
||||
'network': 'itworx-mcp-hub-npm',
|
||||
'npmAttached': None,
|
||||
'frontdoorAttached': None,
|
||||
}
|
||||
if not isinstance(payload, list):
|
||||
return {
|
||||
'status': 'unknown',
|
||||
'network': 'itworx-mcp-hub-npm',
|
||||
'npmAttached': None,
|
||||
'frontdoorAttached': None,
|
||||
}
|
||||
|
||||
npm = []
|
||||
frontdoor = []
|
||||
for raw in payload:
|
||||
if not isinstance(raw, dict):
|
||||
return {
|
||||
'status': 'unknown',
|
||||
'network': 'itworx-mcp-hub-npm',
|
||||
'npmAttached': None,
|
||||
'frontdoorAttached': None,
|
||||
}
|
||||
names = raw.get('Names')
|
||||
if not isinstance(names, list) or any(not isinstance(name, str) for name in names):
|
||||
return {
|
||||
'status': 'unknown',
|
||||
'network': 'itworx-mcp-hub-npm',
|
||||
'npmAttached': None,
|
||||
'frontdoorAttached': None,
|
||||
}
|
||||
name_matches = any(name.lstrip('/') == 'NginxProxyManager' for name in names)
|
||||
image = raw.get('Image')
|
||||
if not isinstance(image, str) or not image:
|
||||
return {
|
||||
'status': 'unknown',
|
||||
'network': 'itworx-mcp-hub-npm',
|
||||
'npmAttached': None,
|
||||
'frontdoorAttached': None,
|
||||
}
|
||||
image_repository = image.rsplit('@', 1)[0]
|
||||
last_component = image_repository.rsplit('/', 1)[-1]
|
||||
if ':' in last_component:
|
||||
image_repository = image_repository.rsplit(':', 1)[0]
|
||||
image_repository = image_repository.lower()
|
||||
if name_matches:
|
||||
if image_repository != 'jlesage/nginx-proxy-manager':
|
||||
return {
|
||||
'status': 'unknown',
|
||||
'network': 'itworx-mcp-hub-npm',
|
||||
'npmAttached': None,
|
||||
'frontdoorAttached': None,
|
||||
}
|
||||
npm.append(raw)
|
||||
labels = raw.get('Labels')
|
||||
if (
|
||||
isinstance(labels, dict)
|
||||
and labels.get('com.docker.compose.project') == 'itworx-forge'
|
||||
and labels.get('com.docker.compose.service') == 'itworx-forge'
|
||||
):
|
||||
frontdoor.append(raw)
|
||||
if len(npm) != 1 or len(frontdoor) != 1:
|
||||
return {
|
||||
'status': 'unknown',
|
||||
'network': 'itworx-mcp-hub-npm',
|
||||
'npmAttached': None,
|
||||
'frontdoorAttached': None,
|
||||
}
|
||||
npm_id = npm[0].get('Id')
|
||||
frontdoor_id = frontdoor[0].get('Id')
|
||||
if (
|
||||
not isinstance(npm_id, str)
|
||||
or not re.fullmatch(r'[0-9a-f]{64}', npm_id)
|
||||
or not isinstance(frontdoor_id, str)
|
||||
or not re.fullmatch(r'[0-9a-f]{64}', frontdoor_id)
|
||||
or npm_id == frontdoor_id
|
||||
):
|
||||
return {
|
||||
'status': 'unknown',
|
||||
'network': 'itworx-mcp-hub-npm',
|
||||
'npmAttached': None,
|
||||
'frontdoorAttached': None,
|
||||
}
|
||||
|
||||
def _attached(raw: dict[str, Any]) -> tuple[str, str] | bool | None:
|
||||
if raw.get('State') != 'running':
|
||||
return False
|
||||
network_settings = raw.get('NetworkSettings')
|
||||
networks = network_settings.get('Networks') if isinstance(network_settings, dict) else None
|
||||
if not isinstance(networks, dict):
|
||||
return None
|
||||
if 'itworx-mcp-hub-npm' not in networks:
|
||||
return False
|
||||
network = networks.get('itworx-mcp-hub-npm')
|
||||
if not isinstance(network, dict):
|
||||
return None
|
||||
network_id = network.get('NetworkID')
|
||||
endpoint_id = network.get('EndpointID')
|
||||
if (
|
||||
not isinstance(network_id, str)
|
||||
or re.fullmatch(r'[0-9a-f]{64}', network_id) is None
|
||||
or not isinstance(endpoint_id, str)
|
||||
or re.fullmatch(r'[0-9a-f]{64}', endpoint_id) is None
|
||||
):
|
||||
return None
|
||||
return network_id, endpoint_id
|
||||
|
||||
npm_membership = _attached(npm[0])
|
||||
frontdoor_membership = _attached(frontdoor[0])
|
||||
if npm_membership is None or frontdoor_membership is None:
|
||||
status = 'unknown'
|
||||
elif npm_membership is False or frontdoor_membership is False:
|
||||
status = 'not_ready'
|
||||
elif npm_membership[0] != frontdoor_membership[0]:
|
||||
status = 'unknown'
|
||||
else:
|
||||
status = 'ready'
|
||||
npm_attached = None if npm_membership is None else npm_membership is not False
|
||||
frontdoor_attached = None if frontdoor_membership is None else frontdoor_membership is not False
|
||||
return {
|
||||
'status': status,
|
||||
'network': 'itworx-mcp-hub-npm',
|
||||
'npmAttached': npm_attached,
|
||||
'frontdoorAttached': frontdoor_attached,
|
||||
}
|
||||
|
||||
def _attach_container_stats(self, containers: list[dict[str, Any]], stats_limit: int) -> None:
|
||||
candidates = [
|
||||
container
|
||||
|
||||
Reference in new issue
Block a user