Skip to content

Commit 486de4d

Browse files
Merge branch 'main' into feature/bgp-neighbors-7.6
2 parents 6b75e0e + 451376c commit 486de4d

17 files changed

Lines changed: 640 additions & 11 deletions

.github/workflows/golangci-lint.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828
with:
2929
persist-credentials: false
3030
- name: Install Go
31-
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
31+
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
3232
with:
3333
go-version: 1.25.x
3434
- name: Install snmp_exporter/generator dependencies

README.md

100644100755
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,9 @@ To improve security, limit permissions to required ones only (least privilege pr
182182
|System/AvailableCertificates | *any* |api/v2/monitor/system/available-certificates |
183183
|System/Central-management/Status | sysgrp.cfg |api/v2/monitor/system/central-management/status|
184184
|System/Fortimanager/Status | sysgrp.cfg |api/v2/monitor/system/fortimanager/status |
185+
|System/Global/Location | sysgrp.cfg |api/v2/cmdb/system/global |
185186
|System/HAStatistics | sysgrp.cfg |api/v2/monitor/system/ha-statistics<br>api/v2/cmdb/system/ha |
187+
|System/Ha-peer | sysgrp.cfg |api/v2/monitor/system/ha-peer |
186188
|System/Interface | netgrp.cfg |api/v2/monitor/system/interface/select |
187189
|System/Interface/Transceivers| *any* |api/v2/monitor/system/interface/transceivers |
188190
|System/LinkMonitor | sysgrp.cfg |api/v2/monitor/system/link-monitor |

metrics.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ Global:
44

55
* _Network/Dns/Latency_
66
* `fortigate_network_dns_latency_`
7+
* _System/Global/Location_
8+
* `fortigate_location_info`
79
* _System/SensorInfo_
810
* `fortigate_sensor_alarm_status`
911
* `fortigate_sensor_fan_rpm`
@@ -12,6 +14,7 @@ Global:
1214
* `fortigate_sensor_thresholds`
1315
* _System/Status_
1416
* `fortigate_version_info`
17+
* `fortigate_system_status_log_disk_state`
1518
* _System/Transceivers_
1619
* `fortigate_interface_transceivers`
1720
* _System/Time/Clock_
@@ -37,6 +40,9 @@ Global:
3740
* `fortigate_system_performance_status_mem_used_bytes`
3841
* _System/HAChecksums_
3942
* `fortigate_ha_member_has_role`
43+
* _System/HAPeer_
44+
* `fortigate_ha_peer_info`
45+
* `fortigate_ha_peer_primary`
4046
* _System/Ntp/Status_
4147
* `fortigate_system_ntp_delay_seconds`
4248
* `fortigate_system_ntp_dispersion_seconds`
@@ -86,6 +92,7 @@ Per-VDOM:
8692
* _System/Interface/Transceivers_
8793
* `fortigate_inteface_transceivers_info`
8894
* _System/SDNConnector_
95+
* `fortigate_system_sdn_connector_state`
8996
* `fortigate_system_sdn_connector_status`
9097
* `fortigate_system_sdn_connector_last_update_seconds`
9198
* _/System/CentralManagement/Status_

pkg/probe/managed_switch.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ func probeManagedSwitch(c http.FortiHTTP, _ *TargetMetadata) ([]prometheus.Metri
235235

236236
// Consider implementing pagination to remove this limit of 1000 entries
237237
var response managedResponse
238-
if err := c.Get("api/v2/monitor/switch-controller/managed-switch", "vdom=*&start=0&poe=true&port_stats=true&transceiver=true&count=1000", &response); err != nil {
238+
if err := c.Get("api/v2/monitor/switch-controller/managed-switch/status", "vdom=*&start=0&poe=true&port_stats=true&transceiver=true&count=1000", &response); err != nil {
239239
log.Printf("Error: %v", err)
240240
return nil, false
241241
}

pkg/probe/managed_switch_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import (
2323

2424
func TestProbeManagedSwitch(t *testing.T) {
2525
c := newFakeClient()
26-
c.prepare("api/v2/monitor/switch-controller/managed-switch", "testdata/managed-switch.jsonnet")
26+
c.prepare("api/v2/monitor/switch-controller/managed-switch/status", "testdata/managed-switch.jsonnet")
2727
r := prometheus.NewPedanticRegistry()
2828
if !testProbe(probeManagedSwitch, c, r) {
2929
t.Errorf("probeManagedSwitchStatus() returned non-success")

pkg/probe/probe.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,9 @@ func (p *Collector) Probe(ctx context.Context, target map[string]string, hc *htt
147147
{"System/AvailableCertificates", probeSystemAvailableCertificates},
148148
{"System/Central-Management/Status", probeSystemCentralManagementStatus},
149149
{"System/Fortimanager/Status", probeSystemFortimanagerStatus},
150+
{"System/Global/Location", probeSystemGlobalLocation},
150151
{"System/HAStatistics", probeSystemHAStatistics},
152+
{"System/Ha-peer", probeSystemHaPeer},
151153
{"System/Interface", probeSystemInterface},
152154
{"System/Interface/Transceivers", probeSystemInterfaceTransceivers},
153155
{"System/LinkMonitor", probeSystemLinkMonitor},
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Copyright The Prometheus Authors
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package probe
15+
16+
import (
17+
"encoding/json"
18+
"log"
19+
20+
"github.com/prometheus/client_golang/prometheus"
21+
22+
"github.com/prometheus-community/fortigate_exporter/pkg/http"
23+
)
24+
25+
func probeSystemGlobalLocation(c http.FortiHTTP, _ *TargetMetadata) ([]prometheus.Metric, bool) {
26+
location := prometheus.NewDesc(
27+
"fortigate_location_info",
28+
"System geographic location (static metadata)",
29+
[]string{"latitude", "longitude"},
30+
nil,
31+
)
32+
33+
type SystemGlobalLocation struct {
34+
Latitude string `json:"gui-device-latitude"`
35+
Longitude string `json:"gui-device-longitude"`
36+
}
37+
38+
type systemGlobalLocationResponse struct {
39+
Results json.RawMessage `json:"results"`
40+
}
41+
42+
var resp systemGlobalLocationResponse
43+
44+
if err := c.Get("api/v2/cmdb/system/global", "vdom=root", &resp); err != nil {
45+
log.Printf("Error: %v", err)
46+
return nil, false
47+
}
48+
49+
var loc SystemGlobalLocation
50+
51+
// Try object first
52+
if err := json.Unmarshal(resp.Results, &loc); err != nil {
53+
// Fallback to array
54+
var arr []SystemGlobalLocation
55+
if err := json.Unmarshal(resp.Results, &arr); err != nil || len(arr) == 0 {
56+
return nil, true
57+
}
58+
loc = arr[0]
59+
}
60+
61+
if loc.Latitude == "" || loc.Longitude == "" {
62+
return nil, true
63+
}
64+
65+
m := []prometheus.Metric{
66+
prometheus.MustNewConstMetric(
67+
location,
68+
prometheus.GaugeValue,
69+
1,
70+
loc.Latitude,
71+
loc.Longitude,
72+
),
73+
}
74+
return m, true
75+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright The Prometheus Authors
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package probe
15+
16+
import (
17+
"strings"
18+
"testing"
19+
20+
"github.com/prometheus/client_golang/prometheus"
21+
"github.com/prometheus/client_golang/prometheus/testutil"
22+
)
23+
24+
func TestSystemGlobalLocation(t *testing.T) {
25+
c := newFakeClient()
26+
c.prepare("api/v2/cmdb/system/global", "testdata/system-global-location.jsonnet")
27+
r := prometheus.NewPedanticRegistry()
28+
if !testProbe(probeSystemGlobalLocation, c, r) {
29+
t.Errorf("probeSystemGlobalLocation() returned non-success")
30+
}
31+
32+
em := `
33+
# HELP fortigate_location_info System geographic location (static metadata)
34+
# TYPE fortigate_location_info gauge
35+
fortigate_location_info{latitude="66.543508", longitude="25.8467468"} 1
36+
`
37+
38+
if err := testutil.GatherAndCompare(r, strings.NewReader(em)); err != nil {
39+
t.Fatalf("metric compare: err %v", err)
40+
}
41+
}

pkg/probe/system_ha_peer.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Copyright The Prometheus Authors
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package probe
15+
16+
import (
17+
"log"
18+
"strconv"
19+
20+
"github.com/prometheus/client_golang/prometheus"
21+
22+
"github.com/prometheus-community/fortigate_exporter/pkg/http"
23+
)
24+
25+
func probeSystemHaPeer(c http.FortiHTTP, meta *TargetMetadata) ([]prometheus.Metric, bool) {
26+
info := prometheus.NewDesc(
27+
"fortigate_ha_peer_info",
28+
"Information about the ha peer.",
29+
[]string{"serial", "vcluster", "hostname", "priority"}, nil,
30+
)
31+
32+
primary := prometheus.NewDesc(
33+
"fortigate_ha_peer_primary",
34+
"True when the peer device is the HA primary.",
35+
[]string{"vcluster", "hostname"}, nil,
36+
)
37+
38+
master := prometheus.NewDesc(
39+
"fortigate_ha_peer_master",
40+
"True when the peer device is the HA master.",
41+
[]string{"vcluster", "hostname"}, nil,
42+
)
43+
44+
type SystemHaPeer struct {
45+
Serial string `json:"serial_no"`
46+
Vcluster int64 `json:"vcluster_id"`
47+
Priority float64 `json:"priority"`
48+
Hostname string `json:"hostname"`
49+
Master bool `json:"master"`
50+
Primary bool `json:"primary"`
51+
}
52+
53+
type SystemHaPeerResult struct {
54+
Result []SystemHaPeer `json:"results"`
55+
}
56+
57+
var res SystemHaPeerResult
58+
if err := c.Get("api/v2/monitor/system/ha-peer", "", &res); err != nil {
59+
log.Printf("Warning: %v", err)
60+
return nil, false
61+
}
62+
m := []prometheus.Metric{}
63+
for _, r := range res.Result {
64+
if meta.VersionMajor >= 7 && meta.VersionMinor >= 4 {
65+
m = append(m, prometheus.MustNewConstMetric(info, prometheus.GaugeValue, 1, r.Serial, strconv.FormatInt(r.Vcluster, 10), r.Hostname, strconv.FormatFloat(r.Priority, 'f', -1, 64)))
66+
if r.Primary {
67+
m = append(m, prometheus.MustNewConstMetric(primary, prometheus.GaugeValue, 1, strconv.FormatInt(r.Vcluster, 10), r.Hostname))
68+
} else {
69+
m = append(m, prometheus.MustNewConstMetric(primary, prometheus.GaugeValue, 0, strconv.FormatInt(r.Vcluster, 10), r.Hostname))
70+
}
71+
if meta.VersionMinor == 4 {
72+
if r.Master {
73+
m = append(m, prometheus.MustNewConstMetric(master, prometheus.GaugeValue, 1, strconv.FormatInt(r.Vcluster, 10), r.Hostname))
74+
} else {
75+
m = append(m, prometheus.MustNewConstMetric(master, prometheus.GaugeValue, 0, strconv.FormatInt(r.Vcluster, 10), r.Hostname))
76+
}
77+
}
78+
} else {
79+
m = append(m, prometheus.MustNewConstMetric(info, prometheus.GaugeValue, -1, "None", "0", "None", "false"))
80+
break
81+
}
82+
}
83+
return m, true
84+
}

pkg/probe/system_ha_peer_test.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright The Prometheus Authors
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package probe
15+
16+
import (
17+
"strings"
18+
"testing"
19+
20+
"github.com/prometheus/client_golang/prometheus"
21+
"github.com/prometheus/client_golang/prometheus/testutil"
22+
)
23+
24+
func TestSystemHaPeerOld(t *testing.T) {
25+
c := newFakeClient()
26+
c.prepare("api/v2/monitor/system/ha-peer", "testdata/system-ha-peer.jsonnet")
27+
r := prometheus.NewPedanticRegistry()
28+
meta := &TargetMetadata{
29+
VersionMajor: 7,
30+
VersionMinor: 0,
31+
}
32+
if !testProbeWithMetadata(probeSystemHaPeer, c, meta, r) {
33+
t.Errorf("probeSystemHaPeer() returned non-success")
34+
}
35+
36+
em := `
37+
# HELP fortigate_ha_peer_info Information about the ha peer.
38+
# TYPE fortigate_ha_peer_info gauge
39+
fortigate_ha_peer_info{hostname="None",priority="false",serial="None",vcluster="0"} -1
40+
`
41+
42+
if err := testutil.GatherAndCompare(r, strings.NewReader(em)); err != nil {
43+
t.Fatalf("metric compare: err %v", err)
44+
}
45+
}
46+
47+
func TestSystemHaPeerAfter74(t *testing.T) {
48+
c := newFakeClient()
49+
c.prepare("api/v2/monitor/system/ha-peer", "testdata/system-ha-peer.jsonnet")
50+
r := prometheus.NewPedanticRegistry()
51+
meta := &TargetMetadata{
52+
VersionMajor: 7,
53+
VersionMinor: 4,
54+
}
55+
if !testProbeWithMetadata(probeSystemHaPeer, c, meta, r) {
56+
t.Errorf("probeSystemHaPeer() returned non-success")
57+
}
58+
59+
em := `
60+
# HELP fortigate_ha_peer_info Information about the ha peer.
61+
# TYPE fortigate_ha_peer_info gauge
62+
fortigate_ha_peer_info{hostname="member-name-1",priority="200",serial="FGT61E4QXXXXXXXX1",vcluster="0"} 1
63+
fortigate_ha_peer_info{hostname="member-name-2",priority="100",serial="FGT61E4QXXXXXXXX2",vcluster="0"} 1
64+
# HELP fortigate_ha_peer_master True when the peer device is the HA master.
65+
# TYPE fortigate_ha_peer_master gauge
66+
fortigate_ha_peer_master{hostname="member-name-1",vcluster="0"} 0
67+
fortigate_ha_peer_master{hostname="member-name-2",vcluster="0"} 1
68+
# HELP fortigate_ha_peer_primary True when the peer device is the HA primary.
69+
# TYPE fortigate_ha_peer_primary gauge
70+
fortigate_ha_peer_primary{hostname="member-name-1",vcluster="0"} 1
71+
fortigate_ha_peer_primary{hostname="member-name-2",vcluster="0"} 0
72+
`
73+
74+
if err := testutil.GatherAndCompare(r, strings.NewReader(em)); err != nil {
75+
t.Fatalf("metric compare: err %v", err)
76+
}
77+
}

0 commit comments

Comments
 (0)