towerops/lib/mix/tasks/import_mibs.ex
Graham McIntire b4f8b40b7f
Include MIB files in Docker image instead of using PVC
- Remove PVC volume mount from k8s/deployment.yaml
- Delete k8s/mib-pvc.yaml (no longer needed)
- Update .gitignore to commit MIB files to git
- Add mix import_mibs task to copy MIBs from LibreNMS
- Add all MIB files from priv/mibs/ to git

This fixes the multi-attach volume error in Kubernetes where new pods
couldn't start because the RWO (ReadWriteOnce) PVC was attached to the
old pod. MIBs are now part of the Docker image and can be used by all
pods simultaneously.
2026-01-19 14:01:03 -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