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 @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