Handle SNMP Counter64 binary values in poller
SNMP Counter64 values (used for interface byte counters) are returned as 8-byte binary data by SNMPKit and need to be decoded to integers before database insertion. Added decode_snmp_value/1 helper that: - Passes through numeric values unchanged - Decodes 8-byte binaries as 64-bit unsigned big-endian integers - Returns nil for unknown formats Updated both sensor and interface polling to use this decoder, preventing DBConnection.EncodeError when trying to insert binary values into integer columns.
This commit is contained in:
parent
3544d117a8
commit
9918f1633c
1 changed files with 45 additions and 15 deletions
|
|
@ -100,23 +100,34 @@ defmodule Towerops.Snmp.PollerWorker do
|
|||
defp poll_sensors(sensors, client_opts, timestamp) do
|
||||
Enum.each(sensors, fn sensor ->
|
||||
case Client.get(client_opts, sensor.sensor_oid) do
|
||||
{:ok, raw_value} when is_number(raw_value) ->
|
||||
# Calculate actual value using divisor
|
||||
value = raw_value / sensor.sensor_divisor
|
||||
{:ok, raw_value} ->
|
||||
decoded_value = decode_snmp_value(raw_value)
|
||||
|
||||
# Determine status based on value (could be enhanced with thresholds)
|
||||
status = "ok"
|
||||
if is_number(decoded_value) do
|
||||
# Calculate actual value using divisor
|
||||
value = decoded_value / sensor.sensor_divisor
|
||||
|
||||
# Save the reading
|
||||
Snmp.create_sensor_reading(%{
|
||||
sensor_id: sensor.id,
|
||||
value: value,
|
||||
status: status,
|
||||
checked_at: timestamp
|
||||
})
|
||||
# Determine status based on value (could be enhanced with thresholds)
|
||||
status = "ok"
|
||||
|
||||
{:ok, _non_numeric} ->
|
||||
Logger.debug("Non-numeric SNMP value for sensor #{sensor.sensor_descr}")
|
||||
# Save the reading
|
||||
Snmp.create_sensor_reading(%{
|
||||
sensor_id: sensor.id,
|
||||
value: value,
|
||||
status: status,
|
||||
checked_at: timestamp
|
||||
})
|
||||
else
|
||||
Logger.debug("Non-numeric SNMP value for sensor #{sensor.sensor_descr}")
|
||||
|
||||
# Save reading with nil value
|
||||
Snmp.create_sensor_reading(%{
|
||||
sensor_id: sensor.id,
|
||||
value: nil,
|
||||
status: "unknown",
|
||||
checked_at: timestamp
|
||||
})
|
||||
end
|
||||
|
||||
{:error, reason} ->
|
||||
Logger.warning("Failed to poll sensor #{sensor.sensor_descr}: #{inspect(reason)}")
|
||||
|
|
@ -160,7 +171,7 @@ defmodule Towerops.Snmp.PollerWorker do
|
|||
results =
|
||||
Enum.map(oids, fn {key, oid} ->
|
||||
case Client.get(client_opts, oid) do
|
||||
{:ok, value} when is_number(value) -> {key, value}
|
||||
{:ok, value} -> {key, decode_snmp_value(value)}
|
||||
_ -> {key, nil}
|
||||
end
|
||||
end)
|
||||
|
|
@ -168,6 +179,25 @@ defmodule Towerops.Snmp.PollerWorker do
|
|||
{:ok, Map.new(results)}
|
||||
end
|
||||
|
||||
# Decode SNMP values, handling Counter64 and other binary types
|
||||
defp decode_snmp_value(value) when is_number(value), do: value
|
||||
|
||||
defp decode_snmp_value(value) when is_binary(value) do
|
||||
# Try to decode as Counter64 (8 bytes, big-endian unsigned integer)
|
||||
case byte_size(value) do
|
||||
8 ->
|
||||
<<counter::unsigned-big-integer-size(64)>> = value
|
||||
counter
|
||||
|
||||
_ ->
|
||||
# Unknown binary format, return nil
|
||||
Logger.debug("Unknown SNMP binary value format, size: #{byte_size(value)}")
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
defp decode_snmp_value(_), do: nil
|
||||
|
||||
defp build_client_opts(equipment) do
|
||||
[
|
||||
ip: equipment.ip_address,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue