master
go 177 lines 5.07 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package panos
4
5 import (
6 "context"
7 "errors"
8 "sort"
9 )
10
11 func (c *Collector) collect(ctx context.Context) (bool, error) {
12 if c.apiClient == nil {
13 return false, errors.New("PAN-OS API client not initialized")
14 }
15 defer c.logSystemInfo()
16
17 var result collectResult
18
19 if result.addContextError(ctx) {
20 return result.hasMetrics, errors.Join(result.errs...)
21 }
22 result.add(c.collectSystemMetrics(ctx))
23 if result.addContextError(ctx) {
24 return result.hasMetrics, errors.Join(result.errs...)
25 }
26 result.add(c.collectHAMetrics(ctx))
27 if result.addContextError(ctx) {
28 return result.hasMetrics, errors.Join(result.errs...)
29 }
30 result.add(c.collectEnvironmentMetrics(ctx))
31 if result.addContextError(ctx) {
32 return result.hasMetrics, errors.Join(result.errs...)
33 }
34 result.add(c.collectLicenseMetrics(ctx))
35 if result.addContextError(ctx) {
36 return result.hasMetrics, errors.Join(result.errs...)
37 }
38 result.add(c.collectIPSecMetrics(ctx))
39 if result.addContextError(ctx) {
40 return result.hasMetrics, errors.Join(result.errs...)
41 }
42
43 peers, err := c.collectBGPPeers(ctx)
44 result.add(false, err)
45 if len(peers) > 0 {
46 monitoredPeers := orderedBGPPeers(peers)
47 result.add(c.collectPeerMetrics(monitoredPeers), nil)
48 result.add(c.collectVRMetrics(peers), nil)
49 }
50
51 return result.hasMetrics, errors.Join(result.errs...)
52 }
53
54 func contextError(ctx context.Context) error {
55 if ctx == nil {
56 return nil
57 }
58 return ctx.Err()
59 }
60
61 type collectResult struct {
62 hasMetrics bool
63 errs []error
64 }
65
66 func (r *collectResult) add(hasMetrics bool, err error) {
67 if hasMetrics {
68 r.hasMetrics = true
69 }
70 if err != nil {
71 r.errs = append(r.errs, err)
72 }
73 }
74
75 func (r *collectResult) addContextError(ctx context.Context) bool {
76 if err := contextError(ctx); err != nil {
77 r.add(false, err)
78 return true
79 }
80 return false
81 }
82
83 func orderedBGPPeers(peers []bgpPeer) []bgpPeer {
84 items := append([]bgpPeer(nil), peers...)
85 sort.SliceStable(items, func(i, j int) bool {
86 return bgpPeerOrderKey(items[i]) < bgpPeerOrderKey(items[j])
87 })
88
89 for i := range items {
90 counters := append([]bgpPrefixCounter(nil), items[i].PrefixCounters...)
91 sort.SliceStable(counters, func(j, k int) bool {
92 return bgpPrefixCounterOrderKey(counters[j]) < bgpPrefixCounterOrderKey(counters[k])
93 })
94 items[i].PrefixCounters = counters
95 }
96
97 return items
98 }
99
100 func bgpPeerOrderKey(peer bgpPeer) string {
101 return firstNonEmpty(peer.VR, "default") + "/" + firstNonEmpty(peer.PeerAddress, "unknown")
102 }
103
104 func bgpPrefixCounterOrderKey(counter bgpPrefixCounter) string {
105 return firstNonEmpty(counter.AFI, "unknown") + "/" + firstNonEmpty(counter.SAFI, "unknown")
106 }
107
108 func (c *Collector) collectPeerMetrics(peers []bgpPeer) bool {
109 if len(peers) == 0 {
110 return false
111 }
112
113 for _, peer := range peers {
114 labels := peerLabelValues(peer)
115 observeStateSetVec(c.metrics.bgp.peerState, peer.State, labels...)
116 c.metrics.bgp.peerUptime.WithLabelValues(labels...).Observe(float64(peer.Uptime))
117 c.metrics.bgp.peerMessagesIn.WithLabelValues(labels...).ObserveTotal(float64(peer.MessagesIn))
118 c.metrics.bgp.peerMessagesOut.WithLabelValues(labels...).ObserveTotal(float64(peer.MessagesOut))
119 c.metrics.bgp.peerUpdatesIn.WithLabelValues(labels...).ObserveTotal(float64(peer.UpdatesIn))
120 c.metrics.bgp.peerUpdatesOut.WithLabelValues(labels...).ObserveTotal(float64(peer.UpdatesOut))
121 c.metrics.bgp.peerFlaps.WithLabelValues(labels...).ObserveTotal(float64(peer.Flaps))
122 c.metrics.bgp.peerEstablishedTransitions.WithLabelValues(labels...).ObserveTotal(float64(peer.Established))
123
124 for _, counter := range peer.PrefixCounters {
125 prefixLabels := prefixLabelValues(peer, counter)
126 c.metrics.bgp.peerPrefixesReceivedTotal.WithLabelValues(prefixLabels...).Observe(float64(counter.IncomingTotal))
127 c.metrics.bgp.peerPrefixesReceivedAccepted.WithLabelValues(prefixLabels...).Observe(float64(counter.IncomingAccepted))
128 c.metrics.bgp.peerPrefixesReceivedRejected.WithLabelValues(prefixLabels...).Observe(float64(counter.IncomingRejected))
129 c.metrics.bgp.peerPrefixesAdvertised.WithLabelValues(prefixLabels...).Observe(float64(counter.OutgoingAdvertised))
130 }
131 }
132
133 return true
134 }
135
136 func (c *Collector) collectVRMetrics(peers []bgpPeer) bool {
137 type vrStats struct {
138 stateCounts map[string]int64
139 total int64
140 established int64
141 }
142
143 stats := make(map[string]*vrStats)
144 for _, peer := range peers {
145 st := stats[peer.VR]
146 if st == nil {
147 st = &vrStats{stateCounts: make(map[string]int64)}
148 stats[peer.VR] = st
149 }
150
151 st.total++
152 if peer.State != "" {
153 st.stateCounts[peer.State]++
154 }
155 if peer.State == "established" {
156 st.established++
157 }
158 }
159
160 vrs := make([]string, 0, len(stats))
161 for vr := range stats {
162 vrs = append(vrs, vr)
163 }
164 sort.Strings(vrs)
165
166 for _, vr := range vrs {
167 st := stats[vr]
168 labels := []string{vr}
169 for _, state := range bgpStates {
170 c.metrics.bgp.vrPeersByState[state].WithLabelValues(labels...).Observe(float64(st.stateCounts[state]))
171 }
172 c.metrics.bgp.vrPeersConfigured.WithLabelValues(labels...).Observe(float64(st.total))
173 c.metrics.bgp.vrPeersEstablished.WithLabelValues(labels...).Observe(float64(st.established))
174 }
175
176 return len(vrs) > 0
177 }