towerops/lib/mix/tasks/import_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

160 lines
4.4 KiB
Elixir

defmodule Mix.Tasks.ImportMibs do
@shortdoc "Import MIB files from LibreNMS to priv/mibs"
@moduledoc """
Imports MIB files from a LibreNMS installation to priv/mibs for inclusion in the Docker image.
## Usage
# Import all MIB files
mix import_mibs --source-path ~/dev/librenms/mibs
# Import specific vendors only
mix import_mibs --source-path ~/dev/librenms/mibs --vendors mikrotik,cisco,ubiquiti
## Options
* `--source-path` - Path to the LibreNMS mibs directory (required)
* `--vendors` - Comma-separated list of vendor directories to import (default: all)
* `--clean` - Remove existing MIBs in priv/mibs before importing (default: false)
## Notes
* Copies MIB files to priv/mibs/ which will be included in the Docker image
* Preserves directory structure from LibreNMS
* Standard MIB files are copied to priv/mibs/ root
* Vendor-specific MIBs are copied to priv/mibs/vendor_name/
* After importing, commit the changes to git so MIBs are included in the container
"""
use Mix.Task
require Logger
def run(args) do
{opts, _} =
OptionParser.parse!(args,
strict: [
source_path: :string,
vendors: :string,
clean: :boolean
]
)
source_path = opts[:source_path] || raise "Missing --source-path argument"
vendors = parse_vendors(opts[:vendors])
clean = opts[:clean] || false
if !File.exists?(source_path) do
raise "Source directory not found: #{source_path}"
end
dest_path = Path.join(["priv", "mibs"])
if clean do
Logger.info("Cleaning priv/mibs...")
_ = File.rm_rf!(dest_path)
File.mkdir_p!(dest_path)
else
File.mkdir_p!(dest_path)
end
case vendors do
:all ->
import_all_vendors(source_path, dest_path)
vendor_list ->
import_specific_vendors(source_path, dest_path, vendor_list)
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 import_all_vendors(source_path, dest_path) do
Logger.info("Discovering entries in #{source_path}...")
entries =
source_path
|> File.ls!()
|> Enum.reject(fn name ->
name == "lost+found" or String.starts_with?(name, ".")
end)
|> Enum.sort()
Logger.info("Found #{length(entries)} entries to import")
# Separate files and directories
{files, directories} =
Enum.split_with(entries, fn name ->
path = Path.join(source_path, name)
File.regular?(path)
end)
# Copy top-level MIB files (standard MIBs)
Logger.info("Copying #{length(files)} standard MIB files...")
Enum.each(files, fn file ->
copy_file(Path.join(source_path, file), Path.join(dest_path, file))
end)
# Copy vendor directories
Logger.info("Copying #{length(directories)} vendor directories...")
Enum.each(directories, fn vendor ->
copy_vendor_directory(source_path, dest_path, vendor)
end)
Logger.info("Import complete!")
Logger.info("Remember to commit the changes: git add priv/mibs && git commit")
end
defp import_specific_vendors(source_path, dest_path, vendors) do
Logger.info("Importing #{length(vendors)} specified vendors...")
Enum.each(vendors, fn vendor ->
vendor_source = Path.join(source_path, vendor)
if File.exists?(vendor_source) do
copy_vendor_directory(source_path, dest_path, vendor)
else
Logger.warning("Vendor directory not found: #{vendor}")
end
end)
Logger.info("Import complete!")
Logger.info("Remember to commit the changes: git add priv/mibs && git commit")
end
defp copy_vendor_directory(source_path, dest_path, vendor) do
vendor_source = Path.join(source_path, vendor)
vendor_dest = Path.join(dest_path, vendor)
Logger.info("Copying #{vendor}...")
case File.cp_r(vendor_source, vendor_dest) do
{:ok, _files} ->
:ok
{:error, reason, file} ->
Logger.error("Failed to copy #{vendor}: #{inspect(reason)} (file: #{file})")
end
end
defp copy_file(source, dest) do
case File.copy(source, dest) do
{:ok, _bytes} ->
:ok
{:error, reason} ->
Logger.error("Failed to copy #{Path.basename(source)}: #{inspect(reason)}")
end
end
end