feat(docker): docker_logs table + docker_009 migration [M79 step 2]
Dedicated host-scoped table for pushed container log lines (one row per line), chained after docker_008. host_id FK CASCADE; twin indexes — (host_id, container_name, ts) for the viewer, ts alone for the age-cutoff prune — mirroring docker_events. Integration schema-shape test asserts columns + both indexes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CAGR73DUowdVFVvYzLXC5C
This commit is contained in:
@@ -75,6 +75,28 @@ def test_events_and_swarm_tables_exist(app):
|
||||
asyncio.run(_go())
|
||||
|
||||
|
||||
@_NEEDS_DB
|
||||
def test_docker_logs_table_shape(app):
|
||||
"""docker_009 created docker_logs: host-scoped, with the twin indexes the
|
||||
viewer (host, container, ts) and the age-cutoff prune (ts) rely on."""
|
||||
from sqlalchemy import text
|
||||
|
||||
async def _go():
|
||||
async with app.db_sessionmaker() as s:
|
||||
cols = {r[0] for r in (await s.execute(text(
|
||||
"SELECT column_name FROM information_schema.columns "
|
||||
"WHERE table_name = 'docker_logs'"))).all()}
|
||||
assert cols, "docker_logs missing entirely"
|
||||
assert {"id", "host_id", "container_name", "ts", "stream", "line"} <= cols
|
||||
idx = {r[0] for r in (await s.execute(text(
|
||||
"SELECT indexname FROM pg_indexes "
|
||||
"WHERE tablename = 'docker_logs'"))).all()}
|
||||
assert "ix_docker_logs_host_container_time" in idx
|
||||
assert "ix_docker_logs_ts" in idx
|
||||
|
||||
asyncio.run(_go())
|
||||
|
||||
|
||||
def _persist_fn(app):
|
||||
"""Resolve persist_host_docker via the registered capability if the docker
|
||||
plugin is loaded, else import it directly (the import is safe only when the
|
||||
|
||||
Reference in New Issue
Block a user