Completes Phase 5 of the unified checks system by enabling automatic check creation during SNMP discovery and providing a backfill tool for existing devices. Discovery Integration: - create_checks_from_discovery/2: Creates checks for all discovered entities (sensors, interfaces, processors, storage) after SNMP discovery completes - Links each check to its source entity via source_id for data lookup - Returns detailed results with counts per type and error tracking - Logs creation results with total counts and any failures Helper Functions: - create_sensor_check/2: Creates snmp_sensor checks with config - create_interface_check/2: Creates snmp_interface checks - create_processor_check/2: Creates snmp_processor checks - create_storage_check/2: Creates snmp_storage checks All checks configured with: - 60-second poll intervals (default) - Auto-discovery source type - Enabled by default - Type-specific configuration in JSONB config field Backfill Tool: - mix backfill.checks: Creates checks for existing SNMP-enabled devices - Supports --dry-run mode for preview - Shows counts per device (sensors, interfaces, processors, storage) - Reports success/failure counts and detailed errors - Safely handles devices without discovery data - Reduced nesting depth using cond and helper functions for credo compliance This enables the unified monitoring system to work with both new discoveries and existing devices, ensuring all SNMP data can be monitored through the unified checks interface. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
103 lines
2.9 KiB
Elixir
103 lines
2.9 KiB
Elixir
defmodule Mix.Tasks.Backfill.Checks do
|
|
@shortdoc "Backfill checks for existing SNMP-enabled devices"
|
|
|
|
@moduledoc """
|
|
Backfill checks for existing devices with SNMP discovery data.
|
|
|
|
This task creates check records for all devices that have existing
|
|
snmp_device records with sensors, interfaces, processors, or storage.
|
|
|
|
Usage:
|
|
mix backfill.checks
|
|
mix backfill.checks --dry-run
|
|
"""
|
|
|
|
use Mix.Task
|
|
|
|
import Ecto.Query
|
|
|
|
alias Towerops.Devices
|
|
alias Towerops.Repo
|
|
alias Towerops.Snmp.Discovery
|
|
|
|
require Logger
|
|
|
|
@impl Mix.Task
|
|
def run(args) do
|
|
Mix.Task.run("app.start")
|
|
|
|
dry_run = "--dry-run" in args
|
|
|
|
if dry_run do
|
|
IO.puts("=== DRY RUN MODE - No changes will be made ===\n")
|
|
end
|
|
|
|
devices =
|
|
Repo.all(
|
|
from d in Devices.Device,
|
|
where: d.snmp_enabled == true,
|
|
preload: [:organization, snmp_device: [:sensors, :interfaces, :processors, :storage]]
|
|
)
|
|
|
|
IO.puts("Found #{length(devices)} SNMP-enabled devices\n")
|
|
|
|
Enum.each(devices, fn device ->
|
|
if device.snmp_device do
|
|
backfill_device_checks(device, dry_run)
|
|
else
|
|
IO.puts("Skipping #{device.name} - no SNMP discovery data")
|
|
end
|
|
end)
|
|
|
|
IO.puts("\n=== Backfill complete ===")
|
|
end
|
|
|
|
defp backfill_device_checks(device, dry_run) do
|
|
snmp_device = device.snmp_device
|
|
sensor_count = length(snmp_device.sensors)
|
|
interface_count = length(snmp_device.interfaces)
|
|
processor_count = length(snmp_device.processors)
|
|
storage_count = length(snmp_device.storage)
|
|
|
|
total = sensor_count + interface_count + processor_count + storage_count
|
|
|
|
cond do
|
|
total == 0 ->
|
|
IO.puts("Skipping #{device.name} - no discovered entities")
|
|
|
|
dry_run ->
|
|
print_device_summary(device, sensor_count, interface_count, processor_count, storage_count)
|
|
IO.puts(" [DRY RUN] Would create #{total} checks")
|
|
|
|
true ->
|
|
print_device_summary(device, sensor_count, interface_count, processor_count, storage_count)
|
|
create_and_report_checks(device, snmp_device)
|
|
end
|
|
end
|
|
|
|
defp print_device_summary(device, sensors, interfaces, processors, storage) do
|
|
IO.puts("\n#{device.name} (#{device.ip_address}):")
|
|
IO.puts(" - #{sensors} sensors")
|
|
IO.puts(" - #{interfaces} interfaces")
|
|
IO.puts(" - #{processors} processors")
|
|
IO.puts(" - #{storage} storage")
|
|
end
|
|
|
|
defp create_and_report_checks(device, snmp_device) do
|
|
result = Discovery.create_checks_from_discovery(device, snmp_device)
|
|
created = result.sensors + result.interfaces + result.processors + result.storage
|
|
|
|
if result.errors == [] do
|
|
IO.puts(" ✓ Created #{created} checks")
|
|
else
|
|
IO.puts(" ✓ Created #{created} checks (#{length(result.errors)} errors)")
|
|
print_errors(result.errors)
|
|
end
|
|
end
|
|
|
|
defp print_errors(errors) do
|
|
Enum.each(errors, fn error ->
|
|
IO.puts(" ⚠ #{error.type}: #{error.message}")
|
|
end)
|
|
end
|
|
end
|