"""Integration (#6115): a host's traffic put down to its containers and NFS mounts, read from plugin_metrics in shared time buckets on Postgres.""" from __future__ import annotations import asyncio import os import uuid from datetime import datetime, timedelta, timezone import pytest pytestmark = pytest.mark.integration @pytest.fixture def app(): if not os.environ.get("STEWARD_DATABASE_URL"): pytest.skip("needs Postgres") from steward.app import create_app return create_app(testing=False) def test_the_host_s_peak_is_put_down_to_its_senders(app): from steward.models.metrics import PluginMetric, PluginMetricLatest from plugins.host_agent.senders import senders now = datetime.now(timezone.utc) host = "senders-host-" + uuid.uuid4().hex[:8] peak, later = now - timedelta(minutes=30), now - timedelta(minutes=10) task = "a" * 25 def m(source, resource, metric, value, at): return PluginMetric(source_module=source, resource_name=resource, metric_name=metric, value=value, recorded_at=at) async def _go(): async with app.db_sessionmaker() as s: async with s.begin(): s.add_all([ m("host_agent", host, "net_tx_bps", 1000.0, peak), m("host_agent", host, "net_tx_bps", 100.0, later), # one service's two tasks add up; another host's don't count m("docker", f"{host}/web.1.{task}", "net_tx_bps", 600.0, peak), m("docker", f"{host}/web.2.{task}", "net_tx_bps", 200.0, peak), m("docker", f"{host}/web.1.{task}", "net_tx_bps", 50.0, later), m("docker", f"{host}x/web.1.{task}", "net_tx_bps", 9999.0, peak), m("host_agent", f"{host}:/nfs/data", "nfs_tx_bps", 100.0, peak), m("host_agent", f"{host}:net:eno1", "net_tx_bps", 1000.0, peak), ]) # the latest-value table names the resources under the host for src, res, metric in (("docker", f"{host}/web.1.{task}", "net_tx_bps"), ("docker", f"{host}/web.2.{task}", "net_tx_bps"), ("docker", f"{host}x/web.1.{task}", "net_tx_bps"), ("host_agent", f"{host}:/nfs/data", "nfs_tx_bps")): await s.merge(PluginMetricLatest(source_module=src, resource_name=res, metric_name=metric, value=1.0, recorded_at=peak)) async with app.db_sessionmaker() as s: return await senders(s, host, now - timedelta(hours=1)) got = asyncio.run(_go()) assert got["host"]["peak_bps"] == 1000.0 and got["bucket_s"] == 60 assert [(r["kind"], r["name"], r["at_host_peak_bps"]) for r in got["senders"]] == [ ("container", "web", 800.0), ("nfs", "/nfs/data", 100.0)] assert got["unaccounted_at_peak_bps"] == 100.0