Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions systemgate/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,10 @@ def vitals():
# container's own filesystem and saying so is the difference between
# telemetry and a misleading number.
disk_path = os.environ.get("SYSTEMGATE_DISK_PATH", "/")
disk = psutil.disk_usage(disk_path)
try:
disk = psutil.disk_usage(disk_path)
except OSError:
disk = None

# Read from psutil itself rather than from the environment, so this reports
# where the numbers came from instead of where they were asked to come from.
Expand All @@ -167,7 +170,8 @@ def vitals():
"cpu_percent": psutil.cpu_percent(interval=0.05),
"cpu_count": psutil.cpu_count(),
"memory": psutil.virtual_memory()._asdict(),
"disk": disk._asdict(),
# null when the disk path cannot be read; source.disk_path says which path.
"disk": disk._asdict() if disk is not None else None,
"load": os.getloadavg() if hasattr(os, "getloadavg") else [0.0, 0.0, 0.0],
"temps": temps,
"source": {
Expand Down Expand Up @@ -214,7 +218,13 @@ def services(limit: int = 80):
try:
connections = psutil.net_connections(kind="inet")
except (psutil.AccessDenied, OSError):
connections = []
return {
"status": "unavailable",
"results": [],
"source": "psutil.net_connections",
"metadata_only": True,
"errors": ["service_enumeration_unavailable"],
}
for conn in connections:
if str(getattr(conn, "status", "") or "") != "LISTEN":
continue
Expand Down
16 changes: 16 additions & 0 deletions tests/test_endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,22 @@ def test_vitals_with_mocked_psutil(tmp_path, monkeypatch):
assert data["memory"]["total"] == 100


def test_vitals_survive_an_unreadable_disk_path(tmp_path, monkeypatch):
import systemgate.main as main

monkeypatch.setenv("SYSTEMGATE_DISK_PATH", str(tmp_path / "missing"))
monkeypatch.setattr(main.psutil, "sensors_temperatures", lambda fahrenheit=False: {}, raising=False)

with make_client(tmp_path, monkeypatch) as client:
response = client.get("/vitals", headers=headers())

assert response.status_code == 200
data = response.json()
assert data["disk"] is None
assert data["source"]["disk_path"] == str(tmp_path / "missing")
assert data["memory"]["total"] > 0


def test_containers_truthfully_reports_unavailable(tmp_path, monkeypatch):
with make_client(tmp_path, monkeypatch) as client:
data = client.get("/containers", headers=headers()).json()
Expand Down
2 changes: 2 additions & 0 deletions tests/test_inventory_limits.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,8 @@ def test_services_survive_a_denied_connection_listing(tmp_path, monkeypatch):
assert response.status_code == 200
assert data["results"] == []
assert data["metadata_only"] is True
assert data["status"] == "unavailable"
assert data["errors"] == ["service_enumeration_unavailable"]


def test_processes_sort_skip_and_clamp(tmp_path, monkeypatch):
Expand Down
Loading