mirror of
https://github.com/h44z/wg-portal.git
synced 2026-09-03 21:36:44 +00:00
metrics: remove deleted peer series (#748)
This commit is contained in:
@@ -136,3 +136,21 @@ func (m *MetricsServer) UpdatePeerMetrics(peer *domain.Peer, status domain.PeerS
|
|||||||
m.peerSendBytesTotal.WithLabelValues(labels...).Set(float64(status.BytesTransmitted))
|
m.peerSendBytesTotal.WithLabelValues(labels...).Set(float64(status.BytesTransmitted))
|
||||||
m.peerIsConnected.WithLabelValues(labels...).Set(internal.BoolToFloat64(status.IsConnected))
|
m.peerIsConnected.WithLabelValues(labels...).Set(internal.BoolToFloat64(status.IsConnected))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeletePeerMetrics removes all Prometheus series for a peer that was deleted
|
||||||
|
// from the WireGuard portal. GaugeVecs retain label values until explicitly
|
||||||
|
// deleted, so leaving these behind makes a deleted peer indistinguishable from
|
||||||
|
// a retained peer that is currently offline.
|
||||||
|
func (m *MetricsServer) DeletePeerMetrics(peer domain.Peer) {
|
||||||
|
labels := []string{
|
||||||
|
string(peer.InterfaceIdentifier),
|
||||||
|
peer.Interface.AddressStr(),
|
||||||
|
string(peer.Identifier),
|
||||||
|
peer.DisplayName,
|
||||||
|
string(peer.UserIdentifier),
|
||||||
|
}
|
||||||
|
m.peerLastHandshakeSeconds.DeleteLabelValues(labels...)
|
||||||
|
m.peerReceivedBytesTotal.DeleteLabelValues(labels...)
|
||||||
|
m.peerSendBytesTotal.DeleteLabelValues(labels...)
|
||||||
|
m.peerIsConnected.DeleteLabelValues(labels...)
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package adapters
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/h44z/wg-portal/internal/domain"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDeletePeerMetricsRemovesAllPeerSeries(t *testing.T) {
|
||||||
|
labels := []string{"interface", "addresses", "id", "name", "user"}
|
||||||
|
m := &MetricsServer{
|
||||||
|
peerIsConnected: prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: "peer_up_test"}, labels),
|
||||||
|
peerLastHandshakeSeconds: prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: "peer_handshake_test"}, labels),
|
||||||
|
peerReceivedBytesTotal: prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: "peer_received_test"}, labels),
|
||||||
|
peerSendBytesTotal: prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: "peer_sent_test"}, labels),
|
||||||
|
}
|
||||||
|
addr, err := domain.CidrFromString("10.0.0.2/32")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
peer := &domain.Peer{
|
||||||
|
Identifier: "peer-id",
|
||||||
|
InterfaceIdentifier: "wg0",
|
||||||
|
DisplayName: "peer",
|
||||||
|
UserIdentifier: "user",
|
||||||
|
Interface: domain.PeerInterfaceConfig{Addresses: []domain.Cidr{addr}},
|
||||||
|
}
|
||||||
|
m.UpdatePeerMetrics(peer, domain.PeerStatus{PeerId: peer.Identifier, IsConnected: true})
|
||||||
|
m.DeletePeerMetrics(*peer)
|
||||||
|
|
||||||
|
for name, collector := range map[string]prometheus.Collector{
|
||||||
|
"up": m.peerIsConnected, "handshake": m.peerLastHandshakeSeconds,
|
||||||
|
"received": m.peerReceivedBytesTotal, "sent": m.peerSendBytesTotal,
|
||||||
|
} {
|
||||||
|
ch := make(chan prometheus.Metric, 1)
|
||||||
|
collector.Collect(ch)
|
||||||
|
close(ch)
|
||||||
|
if _, ok := <-ch; ok {
|
||||||
|
t.Errorf("%s metric remained after peer deletion", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeletePeerMetricsLeavesRetainedPeerSeries(t *testing.T) {
|
||||||
|
labels := []string{"interface", "addresses", "id", "name", "user"}
|
||||||
|
m := &MetricsServer{
|
||||||
|
peerIsConnected: prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: "peer_up_retained_test"}, labels),
|
||||||
|
peerLastHandshakeSeconds: prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: "peer_handshake_retained_test"}, labels),
|
||||||
|
peerReceivedBytesTotal: prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: "peer_received_retained_test"}, labels),
|
||||||
|
peerSendBytesTotal: prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: "peer_sent_retained_test"}, labels),
|
||||||
|
}
|
||||||
|
deletedAddr, err := domain.CidrFromString("10.0.0.2/32")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
retainedAddr, err := domain.CidrFromString("10.0.0.3/32")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
deleted := &domain.Peer{Identifier: "deleted", InterfaceIdentifier: "wg0", DisplayName: "deleted", UserIdentifier: "user", Interface: domain.PeerInterfaceConfig{Addresses: []domain.Cidr{deletedAddr}}}
|
||||||
|
retained := &domain.Peer{Identifier: "retained", InterfaceIdentifier: "wg0", DisplayName: "retained", UserIdentifier: "user", Interface: domain.PeerInterfaceConfig{Addresses: []domain.Cidr{retainedAddr}}}
|
||||||
|
m.UpdatePeerMetrics(deleted, domain.PeerStatus{PeerId: deleted.Identifier, IsConnected: false})
|
||||||
|
m.UpdatePeerMetrics(retained, domain.PeerStatus{PeerId: retained.Identifier, IsConnected: false})
|
||||||
|
m.DeletePeerMetrics(*deleted)
|
||||||
|
|
||||||
|
ch := make(chan prometheus.Metric, 2)
|
||||||
|
m.peerIsConnected.Collect(ch)
|
||||||
|
close(ch)
|
||||||
|
count := 0
|
||||||
|
for range ch {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
if count != 1 {
|
||||||
|
t.Fatalf("expected one retained peer series, got %d", count)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,6 +31,7 @@ type StatisticsDatabaseRepo interface {
|
|||||||
type StatisticsMetricsServer interface {
|
type StatisticsMetricsServer interface {
|
||||||
UpdateInterfaceMetrics(status domain.InterfaceStatus)
|
UpdateInterfaceMetrics(status domain.InterfaceStatus)
|
||||||
UpdatePeerMetrics(peer *domain.Peer, status domain.PeerStatus)
|
UpdatePeerMetrics(peer *domain.Peer, status domain.PeerStatus)
|
||||||
|
DeletePeerMetrics(peer domain.Peer)
|
||||||
}
|
}
|
||||||
|
|
||||||
type StatisticsEventBus interface {
|
type StatisticsEventBus interface {
|
||||||
@@ -433,6 +434,11 @@ func (c *StatisticsCollector) updatePeerMetrics(ctx context.Context, status doma
|
|||||||
|
|
||||||
func (c *StatisticsCollector) connectToMessageBus() {
|
func (c *StatisticsCollector) connectToMessageBus() {
|
||||||
_ = c.bus.Subscribe(app.TopicPeerIdentifierUpdated, c.handlePeerIdentifierChangeEvent)
|
_ = c.bus.Subscribe(app.TopicPeerIdentifierUpdated, c.handlePeerIdentifierChangeEvent)
|
||||||
|
_ = c.bus.Subscribe(app.TopicPeerDeleted, c.handlePeerDeletedEvent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *StatisticsCollector) handlePeerDeletedEvent(peer domain.Peer) {
|
||||||
|
c.ms.DeletePeerMetrics(peer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StatisticsCollector) handlePeerIdentifierChangeEvent(oldIdentifier, newIdentifier domain.PeerIdentifier) {
|
func (c *StatisticsCollector) handlePeerIdentifierChangeEvent(oldIdentifier, newIdentifier domain.PeerIdentifier) {
|
||||||
|
|||||||
Reference in New Issue
Block a user