towerops/lib/mix/tasks/copy_mibs.ex
Graham McIntire 0a4482f974
feat: add 5 new vendor modules and fix dialyzer issues
Vendor modules added:
- Aviat (WTM microwave radios)
- Aruba (wireless controllers and APs)
- CiscoWLC (Cisco wireless LAN controllers)
- Teltonika (RUTOS LTE routers)
- Sub10 (mmWave backhaul radios)

Dialyzer fixes:
- Fix unknown type Devices.t/0 in alert.ex and device.ex
- Fix unmatched_return warnings across multiple files
- Add :exq to PLT for Exq function detection
- Remove dead code in base.ex, dynamic.ex, vendor.ex
- Fix Device.t() type spec to allow nil name field

Tests: 1437 tests, 0 failures
Dialyzer: 0 errors
Credo: no issues
2026-01-22 09:34:50 -06:00

128 lines
3.5 KiB
Elixir

defmodule Mix.Tasks.CopyMibs do
@shortdoc "Copies MIB files from source directory to app MIB directory"
@moduledoc """
Copies MIB files from a source directory to the application's MIB directory.
## Usage
# Copy all MIB files
mix copy_mibs --source-path ~/mibs
# Copy specific vendor MIB directories
mix copy_mibs --source-path ~/mibs --vendors mikrotik,cisco,ubiquiti
"""
use Mix.Task
require Logger
def run(args) do
{opts, _} =
OptionParser.parse!(args,
strict: [
source_path: :string,
vendors: :string,
target_dir: :string
]
)
source_path = opts[:source_path] || raise "Missing --source-path argument"
target_dir = opts[:target_dir] || get_default_target_dir()
vendors = parse_vendors(opts[:vendors])
source_mibs = source_path
if !File.exists?(source_mibs) do
raise "LibreNMS MIB directory not found: #{source_mibs}"
end
# Ensure target directory exists
File.mkdir_p!(target_dir)
case vendors do
:all ->
copy_all_mibs(source_mibs, target_dir)
vendor_list ->
copy_vendor_mibs(source_mibs, target_dir, vendor_list)
end
end
defp get_default_target_dir do
# In development, use priv/mibs; in production use /app/mibs
if Mix.env() == :dev do
Path.join([File.cwd!(), "priv", "mibs"])
else
Application.get_env(:towerops, :mib_dir, "/app/mibs")
end
end
defp parse_vendors(nil), do: :all
defp parse_vendors(""), do: :all
defp parse_vendors(vendors_string) do
vendors_string
|> String.split(",")
|> Enum.map(&String.trim/1)
|> Enum.reject(&(&1 == ""))
end
defp copy_all_mibs(source_dir, target_dir) do
Logger.info("Copying all MIB files from #{source_dir} to #{target_dir}...")
# Use rsync for efficient copying
case System.cmd("rsync", ["-av", "--exclude=.git", "#{source_dir}/", target_dir]) do
{output, 0} ->
Logger.info("Successfully copied MIB files")
Logger.debug(output)
:ok
{error, exit_code} ->
Logger.error("Failed to copy MIB files (exit code #{exit_code}): #{error}")
{:error, :copy_failed}
end
rescue
_e in ErlangError ->
# rsync not found, fall back to File.cp_r
Logger.warning("rsync not found, using File.cp_r (slower)")
copy_mibs_recursive(source_dir, target_dir)
end
defp copy_vendor_mibs(source_dir, target_dir, vendors) do
Logger.info("Copying MIB files for vendors: #{Enum.join(vendors, ", ")}")
results =
Enum.map(vendors, fn vendor ->
source_path = Path.join(source_dir, vendor)
target_path = Path.join(target_dir, vendor)
if File.exists?(source_path) do
Logger.info("Copying #{vendor} MIBs...")
File.mkdir_p!(target_path)
_ = File.cp_r!(source_path, target_path)
{:ok, vendor}
else
Logger.warning("Vendor MIB directory not found: #{vendor}")
{:error, vendor}
end
end)
successes = Enum.count(results, &match?({:ok, _}, &1))
failures = Enum.count(results, &match?({:error, _}, &1))
Logger.info("Copied #{successes} vendor MIB directories (#{failures} not found)")
end
defp copy_mibs_recursive(source_dir, target_dir) do
case File.cp_r(source_dir, target_dir) do
{:ok, _files} ->
Logger.info("Successfully copied MIB files")
:ok
{:error, reason, file} ->
Logger.error("Failed to copy #{file}: #{inspect(reason)}")
{:error, :copy_failed}
end
end
end