-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
enhancement: Wireguard service collector (#5)
This commit introduce Wireguard metrics and documentation improvements.
- Loading branch information
1 parent
de613b3
commit f6a240c
Showing
6 changed files
with
256 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package collector | ||
|
||
import ( | ||
"github.com/AthennaMind/opnsense-exporter/opnsense" | ||
"github.com/go-kit/log" | ||
"github.com/go-kit/log/level" | ||
"github.com/prometheus/client_golang/prometheus" | ||
) | ||
|
||
type WireguardCollector struct { | ||
log log.Logger | ||
subsystem string | ||
instance string | ||
instances *prometheus.Desc | ||
TransferRx *prometheus.Desc | ||
TransferTx *prometheus.Desc | ||
LatestHandshake *prometheus.Desc | ||
} | ||
|
||
func init() { | ||
collectorInstances = append(collectorInstances, &WireguardCollector{ | ||
subsystem: "wireguard", | ||
}) | ||
} | ||
|
||
func (c *WireguardCollector) Name() string { | ||
return c.subsystem | ||
} | ||
|
||
func (c *WireguardCollector) Register(namespace, instanceLabel string, log log.Logger) { | ||
c.log = log | ||
c.instance = instanceLabel | ||
|
||
level.Debug(c.log). | ||
Log("msg", "Registering collector", "collector", c.Name()) | ||
|
||
c.instances = buildPrometheusDesc(c.subsystem, "interfaces_status", | ||
"Wireguard interface (1 = up, 0 = down)", | ||
[]string{"device", "device_type", "device_name"}, | ||
) | ||
|
||
c.TransferRx = buildPrometheusDesc(c.subsystem, "peer_received_bytes_total", | ||
"Bytes received by this wireguard peer", | ||
[]string{"device", "device_type", "device_name", "peer_name"}, | ||
) | ||
|
||
c.TransferTx = buildPrometheusDesc(c.subsystem, "peer_transmitted_bytes_total", | ||
"Bytes transmitted by this wireguard peer", | ||
[]string{"device", "device_type", "device_name", "peer_name"}, | ||
) | ||
|
||
c.LatestHandshake = buildPrometheusDesc(c.subsystem, "peer_last_handshake_seconds", | ||
"Last handshake by peer in seconds", | ||
[]string{"device", "device_type", "device_name", "peer_name"}, | ||
) | ||
} | ||
|
||
func (c *WireguardCollector) Describe(ch chan<- *prometheus.Desc) { | ||
ch <- c.instances | ||
ch <- c.LatestHandshake | ||
ch <- c.TransferRx | ||
ch <- c.TransferTx | ||
} | ||
|
||
func (c *WireguardCollector) update(ch chan<- prometheus.Metric, desc *prometheus.Desc, valueType prometheus.ValueType, value float64, labelValues ...string) { | ||
ch <- prometheus.MustNewConstMetric( | ||
desc, valueType, value, labelValues..., | ||
) | ||
} | ||
|
||
func (c *WireguardCollector) Update(client *opnsense.Client, ch chan<- prometheus.Metric) *opnsense.APICallError { | ||
data, err := client.FetchWireguardConfig() | ||
|
||
if err != nil { | ||
return err | ||
} | ||
|
||
for _, instance := range data.Interfaces { | ||
c.update(ch, c.instances, prometheus.GaugeValue, float64(instance.Status), instance.Device, instance.DeviceType, instance.DeviceName, c.instance) | ||
} | ||
|
||
for _, instance := range data.Peers { | ||
c.update(ch, c.LatestHandshake, prometheus.CounterValue, float64(instance.LatestHandshake), instance.Device, instance.DeviceType, instance.DeviceName, instance.Name, c.instance) | ||
c.update(ch, c.TransferRx, prometheus.CounterValue, float64(instance.TransferRx), instance.Device, instance.DeviceType, instance.DeviceName, instance.Name, c.instance) | ||
c.update(ch, c.TransferTx, prometheus.CounterValue, float64(instance.TransferTx), instance.Device, instance.DeviceType, instance.DeviceName, instance.Name, c.instance) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
package opnsense | ||
|
||
import ( | ||
"github.com/go-kit/log" | ||
"github.com/go-kit/log/level" | ||
) | ||
|
||
type wireguardClientsResponse struct { | ||
Rows []struct { | ||
IfId string `json:"if"` | ||
IfType string `json:"type"` | ||
LatestHandshake float64 `json:"latest-handshake"` | ||
TransferRx float64 `json:"transfer-rx"` | ||
TransferTx float64 `json:"transfer-tx"` | ||
Status string `json:"status"` | ||
Name string `json:"name"` | ||
IfName string `json:"ifname"` | ||
} `json:"rows"` | ||
RowCount int `json:"rowCount"` | ||
Total int `json:"total"` | ||
Current int `json:"current"` | ||
} | ||
|
||
// WGInterfaceStatus is the custom type that represents the status of a Wireguard interface | ||
type WGInterfaceStatus int | ||
|
||
const ( | ||
WGInterfaceStatusDown WGInterfaceStatus = iota | ||
WGInterfaceStatusUp | ||
WGInterfaceStatusUnknown | ||
) | ||
|
||
type WireguardPeers struct { | ||
Device string | ||
DeviceName string | ||
DeviceType string | ||
LatestHandshake float64 | ||
TransferRx float64 | ||
TransferTx float64 | ||
Name string | ||
} | ||
|
||
type WireguardInterfaces struct { | ||
Device string | ||
DeviceType string | ||
Status WGInterfaceStatus | ||
Name string | ||
DeviceName string | ||
} | ||
|
||
type WireguardClients struct { | ||
Peers []WireguardPeers | ||
Interfaces []WireguardInterfaces | ||
} | ||
|
||
// parseWGInterfaceStatus parses a string status to a WGInterfaceStatus type. | ||
func parseWGInterfaceStatus(statusTranslated string, logger log.Logger, originalStatus string) WGInterfaceStatus { | ||
switch statusTranslated { | ||
case "up": | ||
return WGInterfaceStatusUp | ||
case "down": | ||
return WGInterfaceStatusDown | ||
default: | ||
level.Warn(logger). | ||
Log("msg", "unknown wireguard interface status detected", "status", originalStatus) | ||
return WGInterfaceStatusUnknown | ||
} | ||
} | ||
|
||
func (c *Client) FetchWireguardConfig() (WireguardClients, *APICallError) { | ||
var response wireguardClientsResponse | ||
var data WireguardClients | ||
|
||
url, ok := c.endpoints["wireguardClients"] | ||
if !ok { | ||
return data, &APICallError{ | ||
Endpoint: string(url), | ||
Message: "Unable to fetch Wireguard stats", | ||
StatusCode: 0, | ||
} | ||
} | ||
|
||
if err := c.do("GET", url, nil, &response); err != nil { | ||
return data, err | ||
} | ||
|
||
for _, v := range response.Rows { | ||
|
||
if v.IfType == "interface" { | ||
data.Interfaces = append(data.Interfaces, WireguardInterfaces{ | ||
Device: v.IfId, | ||
DeviceType: v.IfType, | ||
Status: parseWGInterfaceStatus(v.Status, c.log, v.Status), | ||
Name: v.Name, | ||
DeviceName: v.IfName, | ||
}) | ||
} | ||
if v.IfType == "peer" { | ||
data.Peers = append(data.Peers, WireguardPeers{ | ||
DeviceType: v.IfType, | ||
LatestHandshake: v.LatestHandshake, | ||
TransferRx: v.TransferRx, | ||
TransferTx: v.TransferTx, | ||
Name: v.Name, | ||
DeviceName: v.IfName, | ||
Device: v.IfId, | ||
}) | ||
} | ||
} | ||
|
||
return data, nil | ||
} |