fix: use agent-collected data for live polling when agent assigned

Modified GraphLive live polling to check for agent assignments and use
agent-collected sensor data from the database instead of doing direct
SNMP polling. This respects the agent assignment and prevents Phoenix
from bypassing the agent for live graph updates.

Also refactored handle_params to reduce nesting depth.
This commit is contained in:
Graham McIntire 2026-02-05 09:21:43 -06:00
parent dd8c97a45f
commit e0592dbf3d
No known key found for this signature in database

View file

@ -2,6 +2,7 @@ defmodule ToweropsWeb.GraphLive.Show do
@moduledoc false
use ToweropsWeb, :live_view
alias Towerops.Agents
alias Towerops.Devices
alias Towerops.Monitoring
alias Towerops.Snmp
@ -18,46 +19,64 @@ defmodule ToweropsWeb.GraphLive.Show do
def handle_params(%{"id" => device_id, "sensor_type" => sensor_type} = params, _, socket) do
organization = socket.assigns.current_scope.organization
# Verify device exists and user has access
case Devices.get_device(device_id) do
nil ->
with {:ok, device} <- find_device(device_id),
:ok <- verify_device_access(device, organization) do
socket = initialize_graph_view(socket, device_id, sensor_type, params)
{:noreply, socket}
else
{:error, :not_found} ->
{:noreply,
socket
|> put_flash(:error, "Device not found")
|> push_navigate(to: ~p"/devices")}
device ->
# Check if device belongs to current organization
if device.organization_id == organization.id do
maybe_subscribe_to_device(socket, device_id)
range = Map.get(params, "range", "24h")
interface_id = Map.get(params, "interface_id")
sensor_id = Map.get(params, "sensor_id")
storage_id = Map.get(params, "storage_id")
socket =
socket
|> assign(:device_id, device_id)
|> assign(:sensor_type, sensor_type)
|> assign(:range, range)
|> assign(:interface_id, interface_id)
|> assign(:sensor_id, sensor_id)
|> assign(:storage_id, storage_id)
|> assign(:is_live_mode, range == "live")
|> maybe_start_live_polling()
|> load_graph_data()
{:noreply, socket}
else
{:noreply,
socket
|> put_flash(:error, "You don't have access to this device")
|> push_navigate(to: ~p"/devices")}
end
{:error, :access_denied} ->
{:noreply,
socket
|> put_flash(:error, "You don't have access to this device")
|> push_navigate(to: ~p"/devices")}
end
end
defp find_device(device_id) do
case Devices.get_device(device_id) do
nil -> {:error, :not_found}
device -> {:ok, device}
end
end
defp verify_device_access(device, organization) do
if device.organization_id == organization.id do
:ok
else
{:error, :access_denied}
end
end
defp initialize_graph_view(socket, device_id, sensor_type, params) do
maybe_subscribe_to_device(socket, device_id)
range = Map.get(params, "range", "24h")
interface_id = Map.get(params, "interface_id")
sensor_id = Map.get(params, "sensor_id")
storage_id = Map.get(params, "storage_id")
# Check if device has agent assignment
has_agent = Agents.get_device_assignment(device_id) != nil
socket
|> assign(:device_id, device_id)
|> assign(:sensor_type, sensor_type)
|> assign(:range, range)
|> assign(:interface_id, interface_id)
|> assign(:sensor_id, sensor_id)
|> assign(:storage_id, storage_id)
|> assign(:is_live_mode, range == "live")
|> assign(:has_agent_assignment, has_agent)
|> maybe_start_live_polling()
|> load_graph_data()
end
defp maybe_subscribe_to_device(socket, device_id) do
_ =
if connected?(socket) do
@ -644,12 +663,19 @@ defmodule ToweropsWeb.GraphLive.Show do
# Poll sensors and update buffer
defp poll_and_update_buffer(socket, device) do
client_opts = build_snmp_client_opts(device)
now = DateTime.utc_now()
timestamp_ms = DateTime.to_unix(now, :millisecond)
# Poll sensors based on graph type
new_points = poll_sensors_for_live_mode(socket.assigns, client_opts, timestamp_ms)
# Check if device has agent assignment
new_points =
if socket.assigns.has_agent_assignment do
# Use agent-collected data from database
fetch_latest_agent_data(socket.assigns, timestamp_ms)
else
# Do direct SNMP polling
client_opts = build_snmp_client_opts(device)
poll_sensors_for_live_mode(socket.assigns, client_opts, timestamp_ms)
end
# Update buffer with new points (rolling window)
{updated_buffer, point_count} =
@ -669,6 +695,29 @@ defmodule ToweropsWeb.GraphLive.Show do
})
end
# Fetch latest sensor data collected by agent
defp fetch_latest_agent_data(assigns, timestamp_ms) do
sensors = get_sensors_for_live_mode(assigns)
sensors
|> Enum.map(fn sensor ->
# Get the most recent sensor reading from the database
case Snmp.get_latest_sensor_reading(sensor.id) do
nil ->
nil
reading ->
%{
sensor_id: sensor.id,
label: sensor.sensor_descr,
value: Float.round(reading.value || 0.0, 1),
timestamp: timestamp_ms
}
end
end)
|> Enum.reject(&is_nil/1)
end
# Build SNMP client options
defp build_snmp_client_opts(device) do
snmp_config = Devices.get_snmp_config(device)