towerops/lib/towerops/monitoring/executor.ex
Graham McIntire 291ecd1054
feat: add full-featured monitoring platform (HTTP/TCP/DNS checks)
Implements Icinga2-style generic check system for comprehensive monitoring.

Phoenix Backend:
- Generic checks table with JSONB config for all check types
- TimescaleDB check_results hypertable for time-series data
- Check executors (HTTP, TCP, DNS)
- CheckWorker with self-scheduling and state transitions
- Extended alerts system for check-based alerting

Check Types: HTTP/HTTPS, TCP, DNS
Architecture: Icinga2 Checkable pattern, soft/hard states, flapping detection

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-12 14:05:31 -06:00

56 lines
1.6 KiB
Elixir

defmodule Towerops.Monitoring.Executor do
@moduledoc """
Dispatcher for executing checks based on check_type.
Routes to type-specific executors (HTTP, TCP, DNS, etc.).
"""
alias Towerops.Monitoring.Check
alias Towerops.Monitoring.Executors.DnsExecutor
alias Towerops.Monitoring.Executors.HttpExecutor
alias Towerops.Monitoring.Executors.TcpExecutor
@doc """
Executes a check and returns the result.
Returns:
- {:ok, response_time_ms, output} on success
- {:error, reason} on failure
"""
def execute(%Check{check_type: "http", config: config, timeout_ms: timeout}) do
HttpExecutor.execute(config, timeout)
end
def execute(%Check{check_type: "tcp", config: config, timeout_ms: timeout}) do
TcpExecutor.execute(config, timeout)
end
def execute(%Check{check_type: "dns", config: config, timeout_ms: timeout}) do
DnsExecutor.execute(config, timeout)
end
def execute(%Check{check_type: "ping"}) do
# Ping is handled by DeviceMonitorWorker, not here
{:error, "Ping checks are handled separately"}
end
def execute(%Check{check_type: "passive"}) do
# Passive checks don't execute - they receive results
{:error, "Passive checks do not execute actively"}
end
def execute(%Check{check_type: type}) do
{:error, "Unknown check type: #{type}"}
end
@doc """
Converts executor result to check status code.
Returns:
- 0 = OK
- 2 = CRITICAL (for errors)
- 3 = UNKNOWN (for unexpected errors)
"""
def result_to_status({:ok, _response_time, _output}), do: 0
def result_to_status({:error, _reason}), do: 2
end