- Escape HEEx template braces in GraphQL/API docs with raw(~S[...]) - Fix test assertions for updated marketing copy and UI text - Extract helper functions in GraphQL resolvers to reduce nesting depth - Create shared ErrorHelpers module for API controllers - Fix ETS race condition in brute force whitelist cache for async tests - Fix property test generators to use ASCII instead of printable unicode - Add alert_severity helper to site_live/show - Update accounts fixtures for explicit user confirmation
132 lines
3.8 KiB
Elixir
132 lines
3.8 KiB
Elixir
defmodule ToweropsWeb.Api.V1.CheckResultsController do
|
|
@moduledoc "API controller for device checks, metrics, and interfaces."
|
|
use ToweropsWeb, :controller
|
|
|
|
alias Towerops.Devices
|
|
alias Towerops.Monitoring
|
|
alias Towerops.Snmp
|
|
|
|
def checks(conn, %{"device_id" => device_id}) do
|
|
organization_id = conn.assigns.current_organization_id
|
|
|
|
case get_org_device(device_id, organization_id) do
|
|
{:ok, device} ->
|
|
checks =
|
|
organization_id
|
|
|> Monitoring.list_checks(device_id: device.id)
|
|
|> Enum.map(fn check ->
|
|
latest = Monitoring.get_latest_check_result(check.id)
|
|
|
|
%{
|
|
id: check.id,
|
|
name: check.name,
|
|
check_type: check.check_type,
|
|
enabled: check.enabled,
|
|
interval_seconds: check.interval_seconds,
|
|
latest_status: latest && latest.status,
|
|
latest_value: latest && latest.value,
|
|
latest_checked_at: latest && latest.checked_at
|
|
}
|
|
end)
|
|
|
|
json(conn, %{data: checks})
|
|
|
|
{:error, status} ->
|
|
conn |> put_status(status) |> json(%{error: "Device not found"})
|
|
end
|
|
end
|
|
|
|
def metrics(conn, %{"device_id" => device_id} = params) do
|
|
organization_id = conn.assigns.current_organization_id
|
|
|
|
case get_org_device(device_id, organization_id) do
|
|
{:ok, device} ->
|
|
check_type = params["sensor_type"] || params["check_type"]
|
|
hours = parse_int(params["hours"], 24)
|
|
from_time = DateTime.add(DateTime.utc_now(), -hours * 3600, :second)
|
|
|
|
checks = Monitoring.list_checks(organization_id, device_id: device.id, check_type: check_type)
|
|
|
|
metrics =
|
|
Enum.map(checks, fn check ->
|
|
results = Monitoring.get_check_results(check.id, from: from_time)
|
|
|
|
%{
|
|
check_id: check.id,
|
|
check_name: check.name,
|
|
check_type: check.check_type,
|
|
data:
|
|
Enum.map(results, fn r ->
|
|
%{timestamp: r.checked_at, value: r.value, status: r.status}
|
|
end)
|
|
}
|
|
end)
|
|
|
|
json(conn, %{data: metrics})
|
|
|
|
{:error, status} ->
|
|
conn |> put_status(status) |> json(%{error: "Device not found"})
|
|
end
|
|
end
|
|
|
|
def interfaces(conn, %{"device_id" => device_id}) do
|
|
organization_id = conn.assigns.current_organization_id
|
|
|
|
case get_org_device(device_id, organization_id) do
|
|
{:ok, device} ->
|
|
device = Towerops.Repo.preload(device, :snmp_device)
|
|
|
|
interfaces =
|
|
case device.snmp_device do
|
|
nil -> []
|
|
snmp_device -> format_interfaces(snmp_device)
|
|
end
|
|
|
|
json(conn, %{data: interfaces})
|
|
|
|
{:error, status} ->
|
|
conn |> put_status(status) |> json(%{error: "Device not found"})
|
|
end
|
|
end
|
|
|
|
defp get_org_device(device_id, organization_id) do
|
|
device = Devices.get_device!(device_id)
|
|
|
|
if device.organization_id == organization_id do
|
|
{:ok, device}
|
|
else
|
|
{:error, :forbidden}
|
|
end
|
|
rescue
|
|
Ecto.NoResultsError -> {:error, :not_found}
|
|
end
|
|
|
|
defp parse_int(nil, default), do: default
|
|
|
|
defp parse_int(val, default) when is_binary(val) do
|
|
case Integer.parse(val) do
|
|
{n, _} -> n
|
|
:error -> default
|
|
end
|
|
end
|
|
|
|
defp parse_int(val, _default) when is_integer(val), do: val
|
|
|
|
defp format_interfaces(snmp_device) do
|
|
snmp_device.id
|
|
|> Snmp.list_interfaces()
|
|
|> Enum.map(fn iface ->
|
|
%{
|
|
id: iface.id,
|
|
if_index: iface.if_index,
|
|
if_name: iface.if_name,
|
|
if_descr: iface.if_descr,
|
|
if_alias: iface.if_alias,
|
|
if_speed: iface.if_speed,
|
|
if_admin_status: iface.if_admin_status,
|
|
if_oper_status: iface.if_oper_status,
|
|
monitored: iface.monitored
|
|
}
|
|
end)
|
|
end
|
|
end
|