507 lines
16 KiB
Elixir
507 lines
16 KiB
Elixir
defmodule Towerops.Proto.TupleEncode do
|
|
@moduledoc """
|
|
Compatibility wrapper for encoding protobuf messages.
|
|
Accepts tagged tuples and converts them to Elixir structs for encoding.
|
|
"""
|
|
|
|
alias Towerops.Proto.Encode
|
|
alias Towerops.Proto.Types
|
|
|
|
# HeartbeatMetadata
|
|
def encode_heartbeat_metadata({:heartbeat_metadata, version, hostname, uptime}) do
|
|
Encode.encode_heartbeat_metadata(%Types.HeartbeatMetadata{
|
|
version: version,
|
|
hostname: hostname,
|
|
uptime_seconds: uptime
|
|
})
|
|
end
|
|
|
|
# HeartbeatResponse
|
|
def encode_heartbeat_response({:heartbeat_response, status}) do
|
|
Encode.encode_heartbeat_response(%Types.HeartbeatResponse{status: status})
|
|
end
|
|
|
|
# SnmpConfig
|
|
def encode_snmp_config({:snmp_config, enabled, version, community, port, transport}) do
|
|
Encode.encode_snmp_config(%Types.SnmpConfig{
|
|
enabled: enabled,
|
|
version: version,
|
|
community: community,
|
|
port: port,
|
|
transport: transport
|
|
})
|
|
end
|
|
|
|
# Sensor
|
|
def encode_sensor({:sensor, id, type, oid, divisor, unit, metadata}) do
|
|
Encode.encode_sensor(%Types.Sensor{
|
|
id: id,
|
|
sensor_type: type,
|
|
oid: oid,
|
|
divisor: divisor,
|
|
unit: unit,
|
|
metadata: metadata
|
|
})
|
|
end
|
|
|
|
# Interface
|
|
def encode_interface({:interface, id, if_index, if_name}) do
|
|
Encode.encode_interface(%Types.Interface{
|
|
id: id,
|
|
if_index: if_index,
|
|
if_name: if_name
|
|
})
|
|
end
|
|
|
|
# Device (complex with nested structures)
|
|
def encode_device({:device, id, name, ip, snmp, poll_interval, sensors, interfaces, monitoring_enabled, check_interval}) do
|
|
snmp_struct =
|
|
case snmp do
|
|
:none ->
|
|
nil
|
|
|
|
{:some, {:snmp_config, enabled, version, community, port, transport}} ->
|
|
%Types.SnmpConfig{
|
|
enabled: enabled,
|
|
version: version,
|
|
community: community,
|
|
port: port,
|
|
transport: transport
|
|
}
|
|
end
|
|
|
|
sensor_structs =
|
|
Enum.map(sensors, fn {:sensor, id, type, oid, divisor, unit, metadata} ->
|
|
%Types.Sensor{
|
|
id: id,
|
|
sensor_type: type,
|
|
oid: oid,
|
|
divisor: divisor,
|
|
unit: unit,
|
|
metadata: metadata
|
|
}
|
|
end)
|
|
|
|
interface_structs =
|
|
Enum.map(interfaces, fn {:interface, id, if_index, if_name} ->
|
|
%Types.Interface{id: id, if_index: if_index, if_name: if_name}
|
|
end)
|
|
|
|
Encode.encode_device(%Types.Device{
|
|
id: id,
|
|
name: name,
|
|
ip_address: ip,
|
|
snmp: snmp_struct,
|
|
poll_interval_seconds: poll_interval,
|
|
sensors: sensor_structs,
|
|
interfaces: interface_structs,
|
|
monitoring_enabled: monitoring_enabled,
|
|
check_interval_seconds: check_interval
|
|
})
|
|
end
|
|
|
|
# AgentConfig
|
|
def encode_agent_config({:agent_config, version, poll_interval, devices, checks}) do
|
|
device_structs = Enum.map(devices, &tuple_device_to_types/1)
|
|
check_structs = Enum.map(checks, &tuple_check_to_types/1)
|
|
|
|
Encode.encode_agent_config(%Types.AgentConfig{
|
|
version: version,
|
|
poll_interval_seconds: poll_interval,
|
|
devices: device_structs,
|
|
checks: check_structs
|
|
})
|
|
end
|
|
|
|
# SensorReading
|
|
def encode_sensor_reading({:sensor_reading, sensor_id, value, status, timestamp}) do
|
|
Encode.encode_sensor_reading(%Types.SensorReading{
|
|
sensor_id: sensor_id,
|
|
value: value,
|
|
status: status,
|
|
timestamp: timestamp
|
|
})
|
|
end
|
|
|
|
# InterfaceStat
|
|
def encode_interface_stat(
|
|
{:interface_stat, interface_id, if_in_octets, if_out_octets, if_in_errors, if_out_errors, if_in_discards,
|
|
if_out_discards, timestamp}
|
|
) do
|
|
Encode.encode_interface_stat(%Types.InterfaceStat{
|
|
interface_id: interface_id,
|
|
if_in_octets: if_in_octets,
|
|
if_out_octets: if_out_octets,
|
|
if_in_errors: if_in_errors,
|
|
if_out_errors: if_out_errors,
|
|
if_in_discards: if_in_discards,
|
|
if_out_discards: if_out_discards,
|
|
timestamp: timestamp
|
|
})
|
|
end
|
|
|
|
# NeighborDiscovery
|
|
def encode_neighbor_discovery(
|
|
{:neighbor_discovery, interface_id, protocol, chassis_id, sys_name, sys_desc, platform, port_id, port_desc,
|
|
address, capabilities, timestamp}
|
|
) do
|
|
Encode.encode_neighbor_discovery(%Types.NeighborDiscovery{
|
|
interface_id: interface_id,
|
|
protocol: protocol,
|
|
remote_chassis_id: chassis_id,
|
|
remote_system_name: sys_name,
|
|
remote_system_description: sys_desc,
|
|
remote_platform: platform,
|
|
remote_port_id: port_id,
|
|
remote_port_description: port_desc,
|
|
remote_address: address,
|
|
remote_capabilities: capabilities,
|
|
timestamp: timestamp
|
|
})
|
|
end
|
|
|
|
# MonitoringCheck
|
|
def encode_monitoring_check({:monitoring_check, device_id, status, response_time_ms, timestamp}) do
|
|
Encode.encode_monitoring_check(%Types.MonitoringCheck{
|
|
device_id: device_id,
|
|
status: status,
|
|
response_time_ms: response_time_ms,
|
|
timestamp: timestamp
|
|
})
|
|
end
|
|
|
|
# Metric
|
|
def encode_metric(tuple_metric) do
|
|
metric_struct =
|
|
case tuple_metric do
|
|
{:sensor_reading_metric, {:sensor_reading, sensor_id, value, status, timestamp}} ->
|
|
{:sensor_reading,
|
|
%Types.SensorReading{
|
|
sensor_id: sensor_id,
|
|
value: value,
|
|
status: status,
|
|
timestamp: timestamp
|
|
}}
|
|
|
|
{:interface_stat_metric,
|
|
{:interface_stat, interface_id, if_in_octets, if_out_octets, if_in_errors, if_out_errors, if_in_discards,
|
|
if_out_discards, timestamp}} ->
|
|
{:interface_stat,
|
|
%Types.InterfaceStat{
|
|
interface_id: interface_id,
|
|
if_in_octets: if_in_octets,
|
|
if_out_octets: if_out_octets,
|
|
if_in_errors: if_in_errors,
|
|
if_out_errors: if_out_errors,
|
|
if_in_discards: if_in_discards,
|
|
if_out_discards: if_out_discards,
|
|
timestamp: timestamp
|
|
}}
|
|
|
|
{:neighbor_discovery_metric,
|
|
{:neighbor_discovery, interface_id, protocol, chassis_id, sys_name, sys_desc, platform, port_id, port_desc,
|
|
address, capabilities, timestamp}} ->
|
|
{:neighbor_discovery,
|
|
%Types.NeighborDiscovery{
|
|
interface_id: interface_id,
|
|
protocol: protocol,
|
|
remote_chassis_id: chassis_id,
|
|
remote_system_name: sys_name,
|
|
remote_system_description: sys_desc,
|
|
remote_platform: platform,
|
|
remote_port_id: port_id,
|
|
remote_port_description: port_desc,
|
|
remote_address: address,
|
|
remote_capabilities: capabilities,
|
|
timestamp: timestamp
|
|
}}
|
|
|
|
{:monitoring_check_metric, {:monitoring_check, device_id, status, response_time_ms, timestamp}} ->
|
|
{:monitoring_check,
|
|
%Types.MonitoringCheck{
|
|
device_id: device_id,
|
|
status: status,
|
|
response_time_ms: response_time_ms,
|
|
timestamp: timestamp
|
|
}}
|
|
|
|
{:check_result_metric, {:check_result, check_id, status, output, response_time_ms, timestamp}} ->
|
|
{:check_result,
|
|
%Types.CheckResult{
|
|
check_id: check_id,
|
|
status: status,
|
|
output: output,
|
|
response_time_ms: response_time_ms,
|
|
timestamp: timestamp
|
|
}}
|
|
end
|
|
|
|
Encode.encode_metric(metric_struct)
|
|
end
|
|
|
|
# MetricBatch
|
|
def encode_metric_batch({:metric_batch, tuple_metrics}) do
|
|
metric_structs = Enum.map(tuple_metrics, &tuple_metric_to_types/1)
|
|
Encode.encode_metric_batch(%Types.MetricBatch{metrics: metric_structs})
|
|
end
|
|
|
|
# CheckResult
|
|
def encode_check_result({:check_result, check_id, status, output, response_time_ms, timestamp}) do
|
|
Encode.encode_check_result(%Types.CheckResult{
|
|
check_id: check_id,
|
|
status: status,
|
|
output: output,
|
|
response_time_ms: response_time_ms,
|
|
timestamp: timestamp
|
|
})
|
|
end
|
|
|
|
# CheckList
|
|
def encode_check_list({:check_list, tuple_checks}) do
|
|
check_structs = Enum.map(tuple_checks, &tuple_check_to_types/1)
|
|
Encode.encode_check_list(%Types.CheckList{checks: check_structs})
|
|
end
|
|
|
|
# SnmpDevice
|
|
def encode_snmp_device(
|
|
{:snmp_device, ip, community, version, port, v3_security_level, v3_username, v3_auth_protocol, v3_auth_password,
|
|
v3_priv_protocol, v3_priv_password, transport}
|
|
) do
|
|
Encode.encode_snmp_device(%Types.SnmpDevice{
|
|
ip: ip,
|
|
community: community,
|
|
version: version,
|
|
port: port,
|
|
v3_security_level: v3_security_level,
|
|
v3_username: v3_username,
|
|
v3_auth_protocol: v3_auth_protocol,
|
|
v3_auth_password: v3_auth_password,
|
|
v3_priv_protocol: v3_priv_protocol,
|
|
v3_priv_password: v3_priv_password,
|
|
transport: transport
|
|
})
|
|
end
|
|
|
|
# SnmpQuery
|
|
def encode_snmp_query({:snmp_query, query_type, oids}) do
|
|
Encode.encode_snmp_query(%Types.SnmpQuery{
|
|
query_type: query_type,
|
|
oids: oids
|
|
})
|
|
end
|
|
|
|
# AgentJobList
|
|
def encode_agent_job_list({:agent_job_list, tuple_jobs}) do
|
|
job_structs = Enum.map(tuple_jobs, &tuple_job_to_types/1)
|
|
Encode.encode_agent_job_list(%Types.AgentJobList{jobs: job_structs})
|
|
end
|
|
|
|
# AgentJob
|
|
def encode_agent_job(tuple_job) do
|
|
job_struct = tuple_job_to_types(tuple_job)
|
|
Encode.encode_agent_job(job_struct)
|
|
end
|
|
|
|
# AgentError
|
|
def encode_agent_error({:agent_error, device_id, job_id, message, timestamp}) do
|
|
Encode.encode_agent_error(%Types.AgentError{
|
|
device_id: device_id,
|
|
job_id: job_id,
|
|
message: message,
|
|
timestamp: timestamp
|
|
})
|
|
end
|
|
|
|
# CredentialTestResult
|
|
def encode_credential_test_result(
|
|
{:credential_test_result, test_id, success, error_message, system_description, timestamp}
|
|
) do
|
|
Encode.encode_credential_test_result(%Types.CredentialTestResult{
|
|
test_id: test_id,
|
|
success: success,
|
|
error_message: error_message,
|
|
system_description: system_description,
|
|
timestamp: timestamp
|
|
})
|
|
end
|
|
|
|
# MikrotikResult
|
|
def encode_mikrotik_result({:mikrotik_result, device_id, job_id, sentences, error, timestamp}) do
|
|
sentence_structs =
|
|
Enum.map(sentences, fn {:mikrotik_sentence, attrs} ->
|
|
%Types.MikrotikSentence{attributes: attrs}
|
|
end)
|
|
|
|
Encode.encode_mikrotik_result(%Types.MikrotikResult{
|
|
device_id: device_id,
|
|
job_id: job_id,
|
|
sentences: sentence_structs,
|
|
error: error,
|
|
timestamp: timestamp
|
|
})
|
|
end
|
|
|
|
# Helper functions for complex conversions
|
|
|
|
defp tuple_metric_to_types(tuple_metric) do
|
|
case tuple_metric do
|
|
{:sensor_reading_metric, {:sensor_reading, sensor_id, value, status, timestamp}} ->
|
|
{:sensor_reading,
|
|
%Types.SensorReading{
|
|
sensor_id: sensor_id,
|
|
value: value,
|
|
status: status,
|
|
timestamp: timestamp
|
|
}}
|
|
|
|
{:interface_stat_metric,
|
|
{:interface_stat, interface_id, if_in_octets, if_out_octets, if_in_errors, if_out_errors, if_in_discards,
|
|
if_out_discards, timestamp}} ->
|
|
{:interface_stat,
|
|
%Types.InterfaceStat{
|
|
interface_id: interface_id,
|
|
if_in_octets: if_in_octets,
|
|
if_out_octets: if_out_octets,
|
|
if_in_errors: if_in_errors,
|
|
if_out_errors: if_out_errors,
|
|
if_in_discards: if_in_discards,
|
|
if_out_discards: if_out_discards,
|
|
timestamp: timestamp
|
|
}}
|
|
|
|
{:neighbor_discovery_metric,
|
|
{:neighbor_discovery, interface_id, protocol, chassis_id, sys_name, sys_desc, platform, port_id, port_desc,
|
|
address, capabilities, timestamp}} ->
|
|
{:neighbor_discovery,
|
|
%Types.NeighborDiscovery{
|
|
interface_id: interface_id,
|
|
protocol: protocol,
|
|
remote_chassis_id: chassis_id,
|
|
remote_system_name: sys_name,
|
|
remote_system_description: sys_desc,
|
|
remote_platform: platform,
|
|
remote_port_id: port_id,
|
|
remote_port_description: port_desc,
|
|
remote_address: address,
|
|
remote_capabilities: capabilities,
|
|
timestamp: timestamp
|
|
}}
|
|
end
|
|
end
|
|
|
|
defp tuple_check_to_types({:check, id, check_type, interval_seconds, timeout_ms, config}) do
|
|
config_struct =
|
|
case config do
|
|
{:http_config,
|
|
{:http_check_config, url, method, expected_status, verify_ssl, headers, body, regex, follow_redirects}} ->
|
|
{:http,
|
|
%Types.HttpCheckConfig{
|
|
url: url,
|
|
method: method,
|
|
expected_status: expected_status,
|
|
verify_ssl: verify_ssl,
|
|
headers: headers,
|
|
body: body,
|
|
regex: regex,
|
|
follow_redirects: follow_redirects
|
|
}}
|
|
|
|
{:tcp_config, {:tcp_check_config, host, port, send, expect}} ->
|
|
{:tcp, %Types.TcpCheckConfig{host: host, port: port, send: send, expect: expect}}
|
|
|
|
{:dns_config, {:dns_check_config, hostname, server, record_type, expected}} ->
|
|
{:dns,
|
|
%Types.DnsCheckConfig{
|
|
hostname: hostname,
|
|
server: server,
|
|
record_type: record_type,
|
|
expected: expected
|
|
}}
|
|
|
|
{:ssl_config, {:ssl_check_config, host, port, warning_days}} ->
|
|
{:ssl, %Types.SslCheckConfig{host: host, port: port, warning_days: warning_days}}
|
|
|
|
:no_config ->
|
|
nil
|
|
end
|
|
|
|
%Types.Check{
|
|
id: id,
|
|
check_type: check_type,
|
|
interval_seconds: interval_seconds,
|
|
timeout_ms: timeout_ms,
|
|
config: config_struct
|
|
}
|
|
end
|
|
|
|
defp tuple_device_to_types(tuple_device) do
|
|
# Stub - implement if needed
|
|
tuple_device
|
|
end
|
|
|
|
defp tuple_job_to_types(
|
|
{:agent_job, job_id, job_type, device_id, snmp_device, queries, mikrotik_device, mikrotik_commands}
|
|
) do
|
|
snmp_device_struct =
|
|
case snmp_device do
|
|
:none ->
|
|
nil
|
|
|
|
{
|
|
:some,
|
|
# credo:disable-for-next-line Credo.Check.Readability.MaxLineLength
|
|
{:snmp_device, ip, community, version, port, v3_security_level, v3_username, v3_auth_protocol, v3_auth_password,
|
|
v3_priv_protocol, v3_priv_password, transport}
|
|
} ->
|
|
%Types.SnmpDevice{
|
|
ip: ip,
|
|
community: community,
|
|
version: version,
|
|
port: port,
|
|
v3_security_level: v3_security_level,
|
|
v3_username: v3_username,
|
|
v3_auth_protocol: v3_auth_protocol,
|
|
v3_auth_password: v3_auth_password,
|
|
v3_priv_protocol: v3_priv_protocol,
|
|
v3_priv_password: v3_priv_password,
|
|
transport: transport
|
|
}
|
|
end
|
|
|
|
query_structs =
|
|
Enum.map(queries, fn {:snmp_query, query_type, oids} ->
|
|
%Types.SnmpQuery{query_type: query_type, oids: oids}
|
|
end)
|
|
|
|
mikrotik_device_struct =
|
|
case mikrotik_device do
|
|
:none ->
|
|
nil
|
|
|
|
{:some, {:mikrotik_device, ip, port, username, password, use_ssl, ssh_port}} ->
|
|
%Types.MikrotikDevice{
|
|
ip: ip,
|
|
port: port,
|
|
username: username,
|
|
password: password,
|
|
use_ssl: use_ssl,
|
|
ssh_port: ssh_port
|
|
}
|
|
end
|
|
|
|
mikrotik_command_structs =
|
|
Enum.map(mikrotik_commands, fn {:mikrotik_command, command, args} ->
|
|
%Types.MikrotikCommand{command: command, args: args}
|
|
end)
|
|
|
|
%Types.AgentJob{
|
|
job_id: job_id,
|
|
job_type: job_type,
|
|
device_id: device_id,
|
|
snmp_device: snmp_device_struct,
|
|
queries: query_structs,
|
|
mikrotik_device: mikrotik_device_struct,
|
|
mikrotik_commands: mikrotik_command_structs
|
|
}
|
|
end
|
|
end
|