Ansible schedule form: structured playbook-variable fields + first-item dropdown defaults #2
@@ -13,8 +13,8 @@ from alembic import context
|
|||||||
|
|
||||||
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
|
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
|
||||||
|
|
||||||
from fabledscryer.models.base import Base
|
from steward.models.base import Base
|
||||||
import fabledscryer.models # noqa: F401
|
import steward.models # noqa: F401
|
||||||
from plugins.docker.models import DockerContainer, DockerMetric # noqa: F401
|
from plugins.docker.models import DockerContainer, DockerMetric # noqa: F401
|
||||||
|
|
||||||
config = context.config
|
config = context.config
|
||||||
@@ -26,14 +26,14 @@ target_metadata = Base.metadata
|
|||||||
|
|
||||||
def _get_url() -> str:
|
def _get_url() -> str:
|
||||||
import yaml
|
import yaml
|
||||||
cfg_path = os.environ.get("FABLEDSCRYER_CONFIG", "config.yaml")
|
cfg_path = os.environ.get("STEWARD_CONFIG", "config.yaml")
|
||||||
try:
|
try:
|
||||||
with open(cfg_path) as f:
|
with open(cfg_path) as f:
|
||||||
cfg = yaml.safe_load(f) or {}
|
cfg = yaml.safe_load(f) or {}
|
||||||
url = cfg.get("database", {}).get("url", "")
|
url = cfg.get("database", {}).get("url", "")
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
url = ""
|
url = ""
|
||||||
return os.environ.get("FABLEDSCRYER_DATABASE__URL", url)
|
return os.environ.get("STEWARD_DATABASE__URL", url)
|
||||||
|
|
||||||
|
|
||||||
def run_migrations_offline() -> None:
|
def run_migrations_offline() -> None:
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import uuid
|
|||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from sqlalchemy import DateTime, Float, Integer, String, Text
|
from sqlalchemy import DateTime, Float, Integer, String, Text
|
||||||
from sqlalchemy.orm import Mapped, mapped_column
|
from sqlalchemy.orm import Mapped, mapped_column
|
||||||
from fabledscryer.models.base import Base
|
from steward.models.base import Base
|
||||||
|
|
||||||
|
|
||||||
class DockerContainer(Base):
|
class DockerContainer(Base):
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
name: docker
|
name: docker
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
description: "Docker container status, resource usage, restart tracking via Docker socket"
|
description: "Docker container status, resource usage, restart tracking via Docker socket"
|
||||||
author: "FabledScryer"
|
author: "Steward"
|
||||||
license: "MIT"
|
license: "MIT"
|
||||||
min_app_version: "0.1.0"
|
min_app_version: "0.1.0"
|
||||||
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
|
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
|
||||||
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/docker"
|
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/docker"
|
||||||
tags:
|
tags:
|
||||||
- containers
|
- containers
|
||||||
- docker
|
- docker
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
# plugins/docker/routes.py
|
# plugins/docker/routes.py
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import json
|
import json
|
||||||
from datetime import datetime, timezone
|
|
||||||
from quart import Blueprint, current_app, render_template, request
|
from quart import Blueprint, current_app, render_template, request
|
||||||
from sqlalchemy import Integer, cast, func, select
|
from sqlalchemy import Integer, cast, func, select
|
||||||
|
|
||||||
from fabledscryer.auth.middleware import require_role
|
from steward.auth.middleware import require_role
|
||||||
from fabledscryer.models.users import UserRole
|
from steward.models.users import UserRole
|
||||||
from fabledscryer.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds
|
from steward.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds
|
||||||
from .models import DockerContainer, DockerMetric
|
from .models import DockerContainer, DockerMetric
|
||||||
|
|
||||||
docker_bp = Blueprint("docker", __name__, template_folder="templates")
|
docker_bp = Blueprint("docker", __name__, template_folder="templates")
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import json
|
|||||||
import logging
|
import logging
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
from fabledscryer.core.scheduler import ScheduledTask
|
from steward.core.scheduler import ScheduledTask
|
||||||
from fabledscryer.core.alerts import record_metric
|
from steward.core.alerts import record_metric
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|||||||
@@ -106,7 +106,6 @@ async def scrape_docker(socket_path: str, include_stopped: bool) -> list[dict]:
|
|||||||
) from exc
|
) from exc
|
||||||
|
|
||||||
results = []
|
results = []
|
||||||
now = datetime.now(timezone.utc)
|
|
||||||
for container, stats in pairs:
|
for container, stats in pairs:
|
||||||
names = container.get("Names") or []
|
names = container.get("Names") or []
|
||||||
name = names[0].lstrip("/") if names else _short_id(container.get("Id", ""))
|
name = names[0].lstrip("/") if names else _short_id(container.get("Id", ""))
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% block title %}Docker — Fabled Scryer{% endblock %}
|
{% block title %}Docker — Steward{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:1.5rem;gap:1rem;flex-wrap:wrap;">
|
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:1.5rem;gap:1rem;flex-wrap:wrap;">
|
||||||
<h1 class="page-title" style="margin-bottom:0;">Docker</h1>
|
<h1 class="page-title" style="margin-bottom:0;">Docker</h1>
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
"""Core HTTP check logic — runs a single monitor check and returns a result dict."""
|
"""Core HTTP check logic — runs a single monitor check and returns a result dict."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
import ssl
|
import ssl
|
||||||
import time
|
import time
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ from alembic import context
|
|||||||
|
|
||||||
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
|
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
|
||||||
|
|
||||||
from fabledscryer.models.base import Base
|
from steward.models.base import Base
|
||||||
import fabledscryer.models # noqa: F401
|
import steward.models # noqa: F401
|
||||||
from plugins.http.models import HttpMonitor, HttpResult # noqa: F401
|
from plugins.http.models import HttpMonitor, HttpResult # noqa: F401
|
||||||
|
|
||||||
config = context.config
|
config = context.config
|
||||||
@@ -26,14 +26,14 @@ target_metadata = Base.metadata
|
|||||||
|
|
||||||
def _get_url() -> str:
|
def _get_url() -> str:
|
||||||
import yaml
|
import yaml
|
||||||
cfg_path = os.environ.get("FABLEDSCRYER_CONFIG", "config.yaml")
|
cfg_path = os.environ.get("STEWARD_CONFIG", "config.yaml")
|
||||||
try:
|
try:
|
||||||
with open(cfg_path) as f:
|
with open(cfg_path) as f:
|
||||||
cfg = yaml.safe_load(f) or {}
|
cfg = yaml.safe_load(f) or {}
|
||||||
url = cfg.get("database", {}).get("url", "")
|
url = cfg.get("database", {}).get("url", "")
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
url = ""
|
url = ""
|
||||||
return os.environ.get("FABLEDSCRYER_DATABASE__URL", url)
|
return os.environ.get("STEWARD_DATABASE__URL", url)
|
||||||
|
|
||||||
|
|
||||||
def run_migrations_offline() -> None:
|
def run_migrations_offline() -> None:
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import uuid
|
|||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from sqlalchemy import Boolean, DateTime, Float, Integer, String, Text
|
from sqlalchemy import Boolean, DateTime, Float, Integer, String, Text
|
||||||
from sqlalchemy.orm import Mapped, mapped_column
|
from sqlalchemy.orm import Mapped, mapped_column
|
||||||
from fabledscryer.models.base import Base
|
from steward.models.base import Base
|
||||||
|
|
||||||
|
|
||||||
class HttpMonitor(Base):
|
class HttpMonitor(Base):
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
name: http
|
name: http
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
description: "Synthetic HTTP endpoint monitoring — status code, response time, content match, TLS expiry"
|
description: "Synthetic HTTP endpoint monitoring — status code, response time, content match, TLS expiry"
|
||||||
author: "FabledScryer"
|
author: "Steward"
|
||||||
license: "MIT"
|
license: "MIT"
|
||||||
min_app_version: "0.1.0"
|
min_app_version: "0.1.0"
|
||||||
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
|
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
|
||||||
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/http"
|
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/http"
|
||||||
tags:
|
tags:
|
||||||
- monitoring
|
- monitoring
|
||||||
- http
|
- http
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
# plugins/http/routes.py
|
# plugins/http/routes.py
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import json
|
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from quart import Blueprint, current_app, render_template, request, redirect, url_for
|
from quart import Blueprint, current_app, render_template, request, redirect, url_for
|
||||||
from sqlalchemy import Integer, cast, func, select
|
from sqlalchemy import Integer, cast, func, select
|
||||||
|
|
||||||
from fabledscryer.auth.middleware import require_role
|
from steward.auth.middleware import require_role
|
||||||
from fabledscryer.models.users import UserRole
|
from steward.models.users import UserRole
|
||||||
from fabledscryer.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds
|
from steward.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds
|
||||||
from .models import HttpMonitor, HttpResult
|
from .models import HttpMonitor, HttpResult
|
||||||
|
|
||||||
http_bp = Blueprint("http", __name__, template_folder="templates")
|
http_bp = Blueprint("http", __name__, template_folder="templates")
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ from __future__ import annotations
|
|||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
from datetime import datetime, timezone, timedelta
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
from fabledscryer.core.scheduler import ScheduledTask
|
from steward.core.scheduler import ScheduledTask
|
||||||
from fabledscryer.core.alerts import record_metric
|
from steward.core.alerts import record_metric
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% block title %}HTTP Monitors — Fabled Scryer{% endblock %}
|
{% block title %}HTTP Monitors — Steward{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:1.5rem;gap:1rem;flex-wrap:wrap;">
|
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:1.5rem;gap:1rem;flex-wrap:wrap;">
|
||||||
<h1 class="page-title" style="margin-bottom:0;">HTTP Monitors</h1>
|
<h1 class="page-title" style="margin-bottom:0;">HTTP Monitors</h1>
|
||||||
|
|||||||
+22
-22
@@ -1,6 +1,6 @@
|
|||||||
# fabledscryer-plugins / index.yaml
|
# steward-plugins / index.yaml
|
||||||
#
|
#
|
||||||
# Plugin catalog for Fabled Scryer.
|
# Plugin catalog for Steward.
|
||||||
# Fetched by the app at: Settings → Plugins → Plugin Catalog
|
# Fetched by the app at: Settings → Plugins → Plugin Catalog
|
||||||
#
|
#
|
||||||
# After updating an entry, commit and push — changes are live within 5 minutes
|
# After updating an entry, commit and push — changes are live within 5 minutes
|
||||||
@@ -16,12 +16,12 @@ plugins:
|
|||||||
- name: http
|
- name: http
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
description: "Synthetic HTTP endpoint monitoring — status code, response time, content match, TLS expiry"
|
description: "Synthetic HTTP endpoint monitoring — status code, response time, content match, TLS expiry"
|
||||||
author: "FabledScryer"
|
author: "Steward"
|
||||||
license: "MIT"
|
license: "MIT"
|
||||||
min_app_version: "0.1.0"
|
min_app_version: "0.1.0"
|
||||||
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
|
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
|
||||||
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/http"
|
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/http"
|
||||||
download_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/releases/download/http-v1.0.0/http.zip"
|
download_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins/releases/download/http-v1.0.0/http.zip"
|
||||||
checksum_sha256: ""
|
checksum_sha256: ""
|
||||||
tags:
|
tags:
|
||||||
- monitoring
|
- monitoring
|
||||||
@@ -32,12 +32,12 @@ plugins:
|
|||||||
- name: docker
|
- name: docker
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
description: "Docker container status, resource usage, and restart tracking via Docker socket"
|
description: "Docker container status, resource usage, and restart tracking via Docker socket"
|
||||||
author: "FabledScryer"
|
author: "Steward"
|
||||||
license: "MIT"
|
license: "MIT"
|
||||||
min_app_version: "0.1.0"
|
min_app_version: "0.1.0"
|
||||||
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
|
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
|
||||||
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/docker"
|
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/docker"
|
||||||
download_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/releases/download/docker-v1.0.0/docker.zip"
|
download_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins/releases/download/docker-v1.0.0/docker.zip"
|
||||||
checksum_sha256: ""
|
checksum_sha256: ""
|
||||||
tags:
|
tags:
|
||||||
- containers
|
- containers
|
||||||
@@ -47,12 +47,12 @@ plugins:
|
|||||||
- name: traefik
|
- name: traefik
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
description: "Traefik reverse proxy metrics and access log integration"
|
description: "Traefik reverse proxy metrics and access log integration"
|
||||||
author: "FabledScryer"
|
author: "Steward"
|
||||||
license: "MIT"
|
license: "MIT"
|
||||||
min_app_version: "0.1.0"
|
min_app_version: "0.1.0"
|
||||||
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
|
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
|
||||||
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/traefik"
|
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/traefik"
|
||||||
download_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/releases/download/traefik-v1.0.0/traefik.zip"
|
download_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins/releases/download/traefik-v1.0.0/traefik.zip"
|
||||||
checksum_sha256: ""
|
checksum_sha256: ""
|
||||||
tags:
|
tags:
|
||||||
- proxy
|
- proxy
|
||||||
@@ -62,12 +62,12 @@ plugins:
|
|||||||
- name: unifi
|
- name: unifi
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
description: "UniFi Network controller integration — WAN health, devices, clients, DPI"
|
description: "UniFi Network controller integration — WAN health, devices, clients, DPI"
|
||||||
author: "FabledScryer"
|
author: "Steward"
|
||||||
license: "MIT"
|
license: "MIT"
|
||||||
min_app_version: "0.1.0"
|
min_app_version: "0.1.0"
|
||||||
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
|
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
|
||||||
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/unifi"
|
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/unifi"
|
||||||
download_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/releases/download/unifi-v1.0.0/unifi.zip"
|
download_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins/releases/download/unifi-v1.0.0/unifi.zip"
|
||||||
checksum_sha256: ""
|
checksum_sha256: ""
|
||||||
tags:
|
tags:
|
||||||
- network
|
- network
|
||||||
@@ -77,12 +77,12 @@ plugins:
|
|||||||
- name: ups
|
- name: ups
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
description: "UPS monitoring via NUT (Network UPS Tools) with Ansible shutdown automation"
|
description: "UPS monitoring via NUT (Network UPS Tools) with Ansible shutdown automation"
|
||||||
author: "FabledScryer"
|
author: "Steward"
|
||||||
license: "MIT"
|
license: "MIT"
|
||||||
min_app_version: "0.1.0"
|
min_app_version: "0.1.0"
|
||||||
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
|
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
|
||||||
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/ups"
|
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/ups"
|
||||||
download_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/releases/download/ups-v1.0.0/ups.zip"
|
download_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins/releases/download/ups-v1.0.0/ups.zip"
|
||||||
checksum_sha256: ""
|
checksum_sha256: ""
|
||||||
tags:
|
tags:
|
||||||
- ups
|
- ups
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
name: snmp
|
name: snmp
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
description: "SNMP polling for network devices — switches, routers, printers, UPSes, etc."
|
description: "SNMP polling for network devices — switches, routers, printers, UPSes, etc."
|
||||||
author: "FabledScryer"
|
author: "Steward"
|
||||||
license: "MIT"
|
license: "MIT"
|
||||||
min_app_version: "0.1.0"
|
min_app_version: "0.1.0"
|
||||||
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
|
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
|
||||||
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/snmp"
|
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/snmp"
|
||||||
tags:
|
tags:
|
||||||
- snmp
|
- snmp
|
||||||
- network
|
- network
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
Synchronous SNMP GET helper, run via executor.
|
Synchronous SNMP GET helper, run via executor.
|
||||||
|
|
||||||
Requires pysnmp-lextudio (maintained pysnmp fork):
|
Requires pysnmp-lextudio (maintained pysnmp fork):
|
||||||
pip install 'fabledscryer[snmp]'
|
pip install 'steward[snmp]'
|
||||||
|
|
||||||
If pysnmp is not installed, poll_device() returns an empty dict and logs a warning.
|
If pysnmp is not installed, poll_device() returns an empty dict and logs a warning.
|
||||||
"""
|
"""
|
||||||
@@ -40,7 +40,7 @@ def poll_device_sync(
|
|||||||
"""
|
"""
|
||||||
if not _pysnmp_available():
|
if not _pysnmp_available():
|
||||||
logger.warning("pysnmp not installed — SNMP polling disabled. "
|
logger.warning("pysnmp not installed — SNMP polling disabled. "
|
||||||
"Install with: pip install 'fabledscryer[snmp]'")
|
"Install with: pip install 'steward[snmp]'")
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
from pysnmp.hlapi import (
|
from pysnmp.hlapi import (
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ from datetime import datetime, timedelta, timezone
|
|||||||
from quart import Blueprint, current_app, render_template, request
|
from quart import Blueprint, current_app, render_template, request
|
||||||
from sqlalchemy import func, select
|
from sqlalchemy import func, select
|
||||||
|
|
||||||
from fabledscryer.auth.middleware import require_role
|
from steward.auth.middleware import require_role
|
||||||
from fabledscryer.models.users import UserRole
|
from steward.models.users import UserRole
|
||||||
from fabledscryer.models.metrics import PluginMetric
|
from steward.models.metrics import PluginMetric
|
||||||
|
|
||||||
snmp_bp = Blueprint("snmp", __name__, template_folder="templates")
|
snmp_bp = Blueprint("snmp", __name__, template_folder="templates")
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from typing import TYPE_CHECKING
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from quart import Quart
|
from quart import Quart
|
||||||
|
|
||||||
from fabledscryer.core.scheduler import ScheduledTask
|
from steward.core.scheduler import ScheduledTask
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -27,16 +27,14 @@ def make_poll_task(app: "Quart") -> ScheduledTask:
|
|||||||
|
|
||||||
|
|
||||||
async def _do_poll(app: "Quart") -> None:
|
async def _do_poll(app: "Quart") -> None:
|
||||||
from datetime import datetime, timezone
|
|
||||||
from .poller import poll_device_sync
|
from .poller import poll_device_sync
|
||||||
from fabledscryer.core.alerts import record_metric
|
from steward.core.alerts import record_metric
|
||||||
|
|
||||||
devices: list[dict] = app.config["PLUGINS"]["snmp"].get("devices", [])
|
devices: list[dict] = app.config["PLUGINS"]["snmp"].get("devices", [])
|
||||||
if not devices:
|
if not devices:
|
||||||
return
|
return
|
||||||
|
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
now = datetime.now(timezone.utc)
|
|
||||||
|
|
||||||
async with app.db_sessionmaker() as session:
|
async with app.db_sessionmaker() as session:
|
||||||
async with session.begin():
|
async with session.begin():
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{# plugins/snmp/templates/snmp/device.html #}
|
{# plugins/snmp/templates/snmp/device.html #}
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% block title %}SNMP — {{ device_name }} — Fabled Scryer{% endblock %}
|
{% block title %}SNMP — {{ device_name }} — Steward{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div style="display:flex;align-items:center;gap:1rem;margin-bottom:1.5rem;flex-wrap:wrap;">
|
<div style="display:flex;align-items:center;gap:1rem;margin-bottom:1.5rem;flex-wrap:wrap;">
|
||||||
<a href="/plugins/snmp/" style="color:var(--text-muted);font-size:0.85rem;">← SNMP</a>
|
<a href="/plugins/snmp/" style="color:var(--text-muted);font-size:0.85rem;">← SNMP</a>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{# plugins/snmp/templates/snmp/index.html #}
|
{# plugins/snmp/templates/snmp/index.html #}
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% block title %}SNMP — Fabled Scryer{% endblock %}
|
{% block title %}SNMP — Steward{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div style="display:flex;align-items:center;gap:1rem;margin-bottom:1.5rem;">
|
<div style="display:flex;align-items:center;gap:1rem;margin-bottom:1.5rem;">
|
||||||
<h1 class="page-title" style="margin:0;">SNMP Devices</h1>
|
<h1 class="page-title" style="margin:0;">SNMP Devices</h1>
|
||||||
|
|||||||
@@ -15,11 +15,11 @@ from sqlalchemy.engine import Connection
|
|||||||
from sqlalchemy.ext.asyncio import async_engine_from_config
|
from sqlalchemy.ext.asyncio import async_engine_from_config
|
||||||
from alembic import context
|
from alembic import context
|
||||||
|
|
||||||
# Make fabledscryer importable
|
# Make steward importable
|
||||||
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
|
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
|
||||||
|
|
||||||
from fabledscryer.models.base import Base
|
from steward.models.base import Base
|
||||||
import fabledscryer.models # noqa: F401 — core models
|
import steward.models # noqa: F401 — core models
|
||||||
from plugins.traefik.models import TraefikMetric # noqa: F401 — plugin model
|
from plugins.traefik.models import TraefikMetric # noqa: F401 — plugin model
|
||||||
|
|
||||||
config = context.config
|
config = context.config
|
||||||
@@ -31,14 +31,14 @@ target_metadata = Base.metadata
|
|||||||
|
|
||||||
def _get_url() -> str:
|
def _get_url() -> str:
|
||||||
import yaml
|
import yaml
|
||||||
cfg_path = os.environ.get("FABLEDSCRYER_CONFIG", "config.yaml")
|
cfg_path = os.environ.get("STEWARD_CONFIG", "config.yaml")
|
||||||
try:
|
try:
|
||||||
with open(cfg_path) as f:
|
with open(cfg_path) as f:
|
||||||
cfg = yaml.safe_load(f) or {}
|
cfg = yaml.safe_load(f) or {}
|
||||||
url = cfg.get("database", {}).get("url", "")
|
url = cfg.get("database", {}).get("url", "")
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
url = ""
|
url = ""
|
||||||
return os.environ.get("FABLEDSCRYER_DATABASE__URL", url)
|
return os.environ.get("STEWARD_DATABASE__URL", url)
|
||||||
|
|
||||||
|
|
||||||
def run_migrations_offline() -> None:
|
def run_migrations_offline() -> None:
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import uuid
|
|||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from sqlalchemy import DateTime, Float, Integer, String, Text
|
from sqlalchemy import DateTime, Float, Integer, String, Text
|
||||||
from sqlalchemy.orm import Mapped, mapped_column
|
from sqlalchemy.orm import Mapped, mapped_column
|
||||||
from fabledscryer.models.base import Base
|
from steward.models.base import Base
|
||||||
|
|
||||||
|
|
||||||
class TraefikMetric(Base):
|
class TraefikMetric(Base):
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
name: traefik
|
name: traefik
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
description: "Traefik reverse proxy metrics and access log integration"
|
description: "Traefik reverse proxy metrics and access log integration"
|
||||||
author: "FabledScryer"
|
author: "Steward"
|
||||||
license: "MIT"
|
license: "MIT"
|
||||||
min_app_version: "0.1.0"
|
min_app_version: "0.1.0"
|
||||||
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
|
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
|
||||||
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/traefik"
|
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/traefik"
|
||||||
tags:
|
tags:
|
||||||
- proxy
|
- proxy
|
||||||
- metrics
|
- metrics
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ from quart import Blueprint, current_app, render_template, request
|
|||||||
from sqlalchemy import Integer, cast, func, select
|
from sqlalchemy import Integer, cast, func, select
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from fabledscryer.auth.middleware import require_role
|
from steward.auth.middleware import require_role
|
||||||
from fabledscryer.models.users import UserRole
|
from steward.models.users import UserRole
|
||||||
from fabledscryer.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds, subsample
|
from steward.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds, subsample
|
||||||
from .models import TraefikAccessSummary, TraefikCert, TraefikGlobalStat, TraefikMetric
|
from .models import TraefikAccessSummary, TraefikCert, TraefikGlobalStat, TraefikMetric
|
||||||
|
|
||||||
traefik_bp = Blueprint("traefik", __name__, template_folder="templates")
|
traefik_bp = Blueprint("traefik", __name__, template_folder="templates")
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import time
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from fabledscryer.core.scheduler import ScheduledTask
|
from steward.core.scheduler import ScheduledTask
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from quart import Quart
|
from quart import Quart
|
||||||
@@ -41,7 +41,6 @@ async def _do_scrape(app: "Quart") -> None:
|
|||||||
global _prev_metrics, _prev_time
|
global _prev_metrics, _prev_time
|
||||||
|
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from sqlalchemy import select
|
|
||||||
from .models import TraefikCert, TraefikGlobalStat, TraefikMetric
|
from .models import TraefikCert, TraefikGlobalStat, TraefikMetric
|
||||||
from .scraper import (
|
from .scraper import (
|
||||||
compute_global_stats,
|
compute_global_stats,
|
||||||
@@ -49,7 +48,7 @@ async def _do_scrape(app: "Quart") -> None:
|
|||||||
extract_certs,
|
extract_certs,
|
||||||
fetch_metrics,
|
fetch_metrics,
|
||||||
)
|
)
|
||||||
from fabledscryer.core.alerts import record_metric
|
from steward.core.alerts import record_metric
|
||||||
|
|
||||||
metrics_url: str = app.config["PLUGINS"]["traefik"]["metrics_url"]
|
metrics_url: str = app.config["PLUGINS"]["traefik"]["metrics_url"]
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{# plugins/traefik/templates/traefik/index.html #}
|
{# plugins/traefik/templates/traefik/index.html #}
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% block title %}Traefik — Fabled Scryer{% endblock %}
|
{% block title %}Traefik — Steward{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div style="display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:0.75rem;margin-bottom:1.5rem;">
|
<div style="display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:0.75rem;margin-bottom:1.5rem;">
|
||||||
<div style="display:flex;align-items:baseline;gap:1rem;">
|
<div style="display:flex;align-items:baseline;gap:1rem;">
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ from alembic import context
|
|||||||
|
|
||||||
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
|
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
|
||||||
|
|
||||||
from fabledscryer.models.base import Base
|
from steward.models.base import Base
|
||||||
import fabledscryer.models # noqa: F401
|
import steward.models # noqa: F401
|
||||||
from plugins.unifi.models import UnifiWanStat, UnifiClientSnapshot, UnifiDevice # noqa: F401
|
from plugins.unifi.models import UnifiWanStat, UnifiClientSnapshot, UnifiDevice # noqa: F401
|
||||||
|
|
||||||
config = context.config
|
config = context.config
|
||||||
@@ -28,14 +28,14 @@ target_metadata = Base.metadata
|
|||||||
|
|
||||||
def _get_url() -> str:
|
def _get_url() -> str:
|
||||||
import yaml
|
import yaml
|
||||||
cfg_path = os.environ.get("FABLEDSCRYER_CONFIG", "config.yaml")
|
cfg_path = os.environ.get("STEWARD_CONFIG", "config.yaml")
|
||||||
try:
|
try:
|
||||||
with open(cfg_path) as f:
|
with open(cfg_path) as f:
|
||||||
cfg = yaml.safe_load(f) or {}
|
cfg = yaml.safe_load(f) or {}
|
||||||
url = cfg.get("database", {}).get("url", "")
|
url = cfg.get("database", {}).get("url", "")
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
url = ""
|
url = ""
|
||||||
return os.environ.get("FABLEDSCRYER_DATABASE__URL", url)
|
return os.environ.get("STEWARD_DATABASE__URL", url)
|
||||||
|
|
||||||
|
|
||||||
def run_migrations_offline() -> None:
|
def run_migrations_offline() -> None:
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import uuid
|
|||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from sqlalchemy import Boolean, DateTime, Float, Integer, String, Text
|
from sqlalchemy import Boolean, DateTime, Float, Integer, String, Text
|
||||||
from sqlalchemy.orm import Mapped, mapped_column
|
from sqlalchemy.orm import Mapped, mapped_column
|
||||||
from fabledscryer.models.base import Base
|
from steward.models.base import Base
|
||||||
|
|
||||||
|
|
||||||
# ── Time-series (one row per scrape) ──────────────────────────────────────────
|
# ── Time-series (one row per scrape) ──────────────────────────────────────────
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
name: unifi
|
name: unifi
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
description: "UniFi Network controller integration — WAN health, devices, clients, DPI"
|
description: "UniFi Network controller integration — WAN health, devices, clients, DPI"
|
||||||
author: "FabledScryer"
|
author: "Steward"
|
||||||
license: "MIT"
|
license: "MIT"
|
||||||
min_app_version: "0.1.0"
|
min_app_version: "0.1.0"
|
||||||
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
|
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
|
||||||
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/unifi"
|
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/unifi"
|
||||||
tags:
|
tags:
|
||||||
- network
|
- network
|
||||||
- unifi
|
- unifi
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
# plugins/unifi/routes.py
|
# plugins/unifi/routes.py
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import json
|
import json
|
||||||
from datetime import datetime, timezone
|
|
||||||
from quart import Blueprint, current_app, render_template, request
|
from quart import Blueprint, current_app, render_template, request
|
||||||
from sqlalchemy import Integer, cast, func, select
|
from sqlalchemy import Integer, cast, func, select
|
||||||
|
|
||||||
from fabledscryer.auth.middleware import require_role
|
from steward.auth.middleware import require_role
|
||||||
from fabledscryer.models.users import UserRole
|
from steward.models.users import UserRole
|
||||||
from fabledscryer.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds, subsample
|
from steward.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds
|
||||||
from .models import (
|
from .models import (
|
||||||
UnifiAlarm, UnifiClientSnapshot, UnifiDevice, UnifiDpiSnapshot,
|
UnifiAlarm, UnifiClientSnapshot, UnifiDevice, UnifiDpiSnapshot,
|
||||||
UnifiEvent, UnifiFwRule, UnifiKnownClient, UnifiNetwork,
|
UnifiEvent, UnifiFwRule, UnifiKnownClient, UnifiNetwork,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import logging
|
|||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from fabledscryer.core.scheduler import ScheduledTask
|
from steward.core.scheduler import ScheduledTask
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from quart import Quart
|
from quart import Quart
|
||||||
@@ -35,7 +35,7 @@ async def _do_poll(app: "Quart") -> None:
|
|||||||
|
|
||||||
from .client import UnifiClient
|
from .client import UnifiClient
|
||||||
from .models import UnifiClientSnapshot, UnifiDevice, UnifiWanStat
|
from .models import UnifiClientSnapshot, UnifiDevice, UnifiWanStat
|
||||||
from fabledscryer.core.alerts import record_metric
|
from steward.core.alerts import record_metric
|
||||||
|
|
||||||
cfg = app.config["PLUGINS"]["unifi"]
|
cfg = app.config["PLUGINS"]["unifi"]
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{# plugins/unifi/templates/unifi/index.html #}
|
{# plugins/unifi/templates/unifi/index.html #}
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% block title %}UniFi — Fabled Scryer{% endblock %}
|
{% block title %}UniFi — Steward{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div style="display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:0.75rem;margin-bottom:1.25rem;">
|
<div style="display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:0.75rem;margin-bottom:1.25rem;">
|
||||||
<div style="display:flex;align-items:baseline;gap:1rem;">
|
<div style="display:flex;align-items:baseline;gap:1rem;">
|
||||||
|
|||||||
@@ -3,13 +3,12 @@ from __future__ import annotations
|
|||||||
import asyncio
|
import asyncio
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
from quart import (
|
from quart import (
|
||||||
Blueprint, Response, current_app, redirect, render_template,
|
Blueprint, Response, current_app, render_template,
|
||||||
request, session, url_for,
|
request, session,
|
||||||
)
|
)
|
||||||
from sqlalchemy import select, update
|
from sqlalchemy import select
|
||||||
|
|
||||||
from steward.ansible import executor, sources as src_module
|
from steward.ansible import executor, sources as src_module
|
||||||
from steward.auth.middleware import require_role
|
from steward.auth.middleware import require_role
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ we trust the HTTPS connection to the discovery-documented token/userinfo endpoin
|
|||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import base64
|
import base64
|
||||||
import hashlib
|
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
# steward/core/plugin_manager.py
|
# steward/core/plugin_manager.py
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import hashlib
|
import hashlib
|
||||||
import importlib
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ Called by the scheduler (hourly check) or triggered manually from Settings.
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
import smtplib
|
|
||||||
import ssl
|
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta, timezone
|
||||||
from email.message import EmailMessage
|
from email.message import EmailMessage
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ target_metadata = Base.metadata
|
|||||||
|
|
||||||
|
|
||||||
def get_url() -> str:
|
def get_url() -> str:
|
||||||
import os, yaml
|
import os
|
||||||
|
import yaml
|
||||||
|
|
||||||
def _env(suffix: str) -> str | None:
|
def _env(suffix: str) -> str | None:
|
||||||
return os.environ.get(f"STEWARD_{suffix}")
|
return os.environ.get(f"STEWARD_{suffix}")
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
# steward/settings/routes.py
|
# steward/settings/routes.py
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from quart import Blueprint, current_app, render_template, request, redirect, url_for, session
|
from quart import Blueprint, current_app, render_template, request, redirect, url_for, session
|
||||||
@@ -9,7 +8,7 @@ from steward.auth.middleware import require_role
|
|||||||
from steward.core.audit import log_audit
|
from steward.core.audit import log_audit
|
||||||
from steward.models.users import UserRole
|
from steward.models.users import UserRole
|
||||||
from steward.core.settings import (
|
from steward.core.settings import (
|
||||||
DEFAULTS, get_all_settings, set_setting,
|
get_all_settings, set_setting,
|
||||||
to_smtp_cfg, to_webhook_cfg, to_ansible_cfg, to_plugins_cfg,
|
to_smtp_cfg, to_webhook_cfg, to_ansible_cfg, to_plugins_cfg,
|
||||||
to_oidc_cfg, to_ldap_cfg,
|
to_oidc_cfg, to_ldap_cfg,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -144,12 +144,12 @@
|
|||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Admin group DN</label>
|
<label>Admin group DN</label>
|
||||||
<input type="text" name="ldap.admin_group_dn" value="{{ settings['ldap.admin_group_dn'] }}"
|
<input type="text" name="ldap.admin_group_dn" value="{{ settings['ldap.admin_group_dn'] }}"
|
||||||
placeholder="cn=scryer-admins,ou=groups,dc=example,dc=com">
|
placeholder="cn=steward-admins,ou=groups,dc=example,dc=com">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Operator group DN</label>
|
<label>Operator group DN</label>
|
||||||
<input type="text" name="ldap.operator_group_dn" value="{{ settings['ldap.operator_group_dn'] }}"
|
<input type="text" name="ldap.operator_group_dn" value="{{ settings['ldap.operator_group_dn'] }}"
|
||||||
placeholder="cn=scryer-operators,ou=groups,dc=example,dc=com">
|
placeholder="cn=steward-operators,ou=groups,dc=example,dc=com">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,7 @@
|
|||||||
<div style="margin-bottom:2rem;max-width:720px;">
|
<div style="margin-bottom:2rem;max-width:720px;">
|
||||||
<div class="section-title" style="margin-bottom:0.75rem;">Plugin Repositories</div>
|
<div class="section-title" style="margin-bottom:0.75rem;">Plugin Repositories</div>
|
||||||
<p style="color:var(--text-muted);font-size:0.84rem;margin-bottom:0.75rem;">
|
<p style="color:var(--text-muted);font-size:0.84rem;margin-bottom:0.75rem;">
|
||||||
Repositories are remote <code>index.yaml</code> files that Scryer checks for available
|
Repositories are remote <code>index.yaml</code> files that Steward checks for available
|
||||||
and updated plugins. Add repos from other developers to expand the plugin catalog.
|
and updated plugins. Add repos from other developers to expand the plugin catalog.
|
||||||
</p>
|
</p>
|
||||||
{% include "settings/_plugin_repos.html" %}
|
{% include "settings/_plugin_repos.html" %}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import pytest
|
import pytest
|
||||||
import pytest_asyncio
|
import pytest_asyncio
|
||||||
from pathlib import Path
|
|
||||||
import textwrap
|
import textwrap
|
||||||
from steward.app import create_app
|
from steward.app import create_app
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import urllib.error
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
from plugins.host_agent import agent as a
|
from plugins.host_agent import agent as a
|
||||||
|
|
||||||
@@ -55,10 +56,6 @@ def test_build_payload_wraps_samples():
|
|||||||
assert payload["samples"][0]["cpu_pct"] == 5.0
|
assert payload["samples"][0]["cpu_pct"] == 5.0
|
||||||
|
|
||||||
|
|
||||||
import urllib.error
|
|
||||||
from unittest.mock import MagicMock, patch
|
|
||||||
|
|
||||||
|
|
||||||
def test_post_payload_success():
|
def test_post_payload_success():
|
||||||
from plugins.host_agent import agent as a
|
from plugins.host_agent import agent as a
|
||||||
captured = {}
|
captured = {}
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ from plugins.host_agent.agent import RingBuffer
|
|||||||
|
|
||||||
def test_ring_buffer_preserves_order():
|
def test_ring_buffer_preserves_order():
|
||||||
rb = RingBuffer(maxlen=3)
|
rb = RingBuffer(maxlen=3)
|
||||||
rb.push(1); rb.push(2); rb.push(3)
|
rb.push(1)
|
||||||
|
rb.push(2)
|
||||||
|
rb.push(3)
|
||||||
assert list(rb.drain()) == [1, 2, 3]
|
assert list(rb.drain()) == [1, 2, 3]
|
||||||
assert len(rb) == 0
|
assert len(rb) == 0
|
||||||
|
|
||||||
@@ -17,7 +19,8 @@ def test_ring_buffer_drops_oldest_when_full():
|
|||||||
|
|
||||||
def test_ring_buffer_drain_clears_and_is_atomic():
|
def test_ring_buffer_drain_clears_and_is_atomic():
|
||||||
rb = RingBuffer(maxlen=5)
|
rb = RingBuffer(maxlen=5)
|
||||||
rb.push("a"); rb.push("b")
|
rb.push("a")
|
||||||
|
rb.push("b")
|
||||||
out = list(rb.drain())
|
out = list(rb.drain())
|
||||||
rb.push("c")
|
rb.push("c")
|
||||||
assert out == ["a", "b"]
|
assert out == ["a", "b"]
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
import subprocess
|
import subprocess
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
|
||||||
from jinja2 import Environment, FileSystemLoader
|
from jinja2 import Environment, FileSystemLoader
|
||||||
|
|
||||||
from plugins.host_agent.routes import _agent_version, AGENT_SOURCE_PATH
|
from plugins.host_agent.routes import _agent_version, AGENT_SOURCE_PATH
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import os
|
|
||||||
import textwrap
|
import textwrap
|
||||||
import pytest
|
import pytest
|
||||||
from steward.config import load_bootstrap
|
from steward.config import load_bootstrap
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import pytest
|
|
||||||
from steward.models.users import User, UserRole
|
from steward.models.users import User, UserRole
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
"""Regression guard: shipped code must not reference old project names.
|
||||||
|
|
||||||
|
The FabledScryer -> Roundtable -> Steward renames repeatedly left stale package
|
||||||
|
imports behind in the (then separate) plugins (e.g. `from fabledscryer.models...`),
|
||||||
|
silently breaking every non-host_agent plugin. Now that plugins are folded in-tree
|
||||||
|
and version with core, this test fails loudly if either legacy name reappears in
|
||||||
|
the shipped Python / templates / plugin manifests.
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
_ROOT = Path(__file__).resolve().parent.parent
|
||||||
|
_TREES = [_ROOT / "steward", _ROOT / "plugins"]
|
||||||
|
_EXTENSIONS = {".py", ".yaml", ".yml", ".html", ".j2"}
|
||||||
|
_FORBIDDEN = ("scryer", "roundtable") # case-insensitive; old project names
|
||||||
|
|
||||||
|
|
||||||
|
def _shipped_files():
|
||||||
|
for tree in _TREES:
|
||||||
|
for path in tree.rglob("*"):
|
||||||
|
if path.suffix in _EXTENSIONS and "__pycache__" not in path.parts:
|
||||||
|
yield path
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("name", _FORBIDDEN)
|
||||||
|
def test_no_legacy_project_name(name):
|
||||||
|
offenders = [
|
||||||
|
str(p.relative_to(_ROOT))
|
||||||
|
for p in _shipped_files()
|
||||||
|
if name in p.read_text(encoding="utf-8", errors="ignore").lower()
|
||||||
|
]
|
||||||
|
assert not offenders, f"legacy name {name!r} found in shipped code: {offenders}"
|
||||||
Reference in New Issue
Block a user