From a0f2dfca46a8d35ee565ae5c249bebeebb91213e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96rnfeldt=20Philip=20=2866140321=29?= Date: Tue, 12 Aug 2025 13:43:03 +0200 Subject: [PATCH 1/7] System ha peer information added MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Örnfeldt Philip (66140321) --- README.md | 3 + pkg/probe/probe.go | 1 + pkg/probe/system_ha_peer.go | 60 +++++++++++++++++++ pkg/probe/system_ha_peer_test.go | 70 +++++++++++++++++++++++ pkg/probe/testdata/system-ha-peer.jsonnet | 27 +++++++++ 5 files changed, 161 insertions(+) create mode 100644 pkg/probe/system_ha_peer.go create mode 100644 pkg/probe/system_ha_peer_test.go create mode 100644 pkg/probe/testdata/system-ha-peer.jsonnet diff --git a/README.md b/README.md index 2b843beb..bb57222a 100755 --- a/README.md +++ b/README.md @@ -51,6 +51,8 @@ Global: * `fortigate_current_sessions` * _System/HAChecksums_ * `fortigate_ha_member_has_role` + * _System/HaPeer_ + * `fortigate_ha_peer_priority` * _License/Status_ * `fortigate_license_vdom_usage` * `fortigate_license_vdom_max` @@ -414,6 +416,7 @@ To improve security, limit permissions to required ones only (least privilege pr |System/AvailableCertificates | *any* |api/v2/monitor/system/available-certificates | |System/Fortimanager/Status | sysgrp.cfg |api/v2/monitor/system/fortimanager/status | |System/HAStatistics | sysgrp.cfg |api/v2/monitor/system/ha-statistics
api/v2/cmdb/system/ha | +|System/Ha-peer | sysgrp.cfg |api/v2/monitor/system/ha-peer | |System/Interface | netgrp.cfg |api/v2/monitor/system/interface/select | |System/LinkMonitor | sysgrp.cfg |api/v2/monitor/system/link-monitor | |System/Resource/Usage | sysgrp.cfg |api/v2/monitor/system/resource/usage | diff --git a/pkg/probe/probe.go b/pkg/probe/probe.go index 88d76fe6..4351f171 100644 --- a/pkg/probe/probe.go +++ b/pkg/probe/probe.go @@ -143,6 +143,7 @@ func (p *ProbeCollector) Probe(ctx context.Context, target map[string]string, hc {"System/AvailableCertificates", probeSystemAvailableCertificates}, {"System/Fortimanager/Status", probeSystemFortimanagerStatus}, {"System/HAStatistics", probeSystemHAStatistics}, + {"System/Ha-peer", probeSystemHaPeer}, {"System/Interface", probeSystemInterface}, {"System/LinkMonitor", probeSystemLinkMonitor}, {"System/Resource/Usage", probeSystemResourceUsage}, diff --git a/pkg/probe/system_ha_peer.go b/pkg/probe/system_ha_peer.go new file mode 100644 index 00000000..ce268452 --- /dev/null +++ b/pkg/probe/system_ha_peer.go @@ -0,0 +1,60 @@ +// Copyright 2025 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package probe + +import ( + "log" + "strconv" + + "github.com/prometheus-community/fortigate_exporter/pkg/http" + "github.com/prometheus/client_golang/prometheus" +) + +func probeSystemHaPeer (c http.FortiHTTP, meta *TargetMetadata) ([]prometheus.Metric, bool) { + var ( + Priority = prometheus.NewDesc( + "fortigate_ha_peer_priority", + "Priority level of the HA peer device.", + []string{"serial","vcluster","hostname","master","primary"}, nil, + ) + ) + + type SystemHaPeer struct { + Serial string `json:"serial_no"` + Vcluster int64 `json:"vcluster_id"` + Priority float64 `json:"priority"` + Hostname string `json:"hostname"` + Master bool `json:"master"` + Primary bool `json:"primary"` + } + + type SystemHaPeerResult struct { + Result []SystemHaPeer `json:"results"` + } + + var res SystemHaPeerResult + if err := c.Get("api/v2/monitor/system/ha-peer", "", &res); err != nil { + log.Printf("Warning: %v", err) + return nil, false + } + m := []prometheus.Metric{} + for _, r := range res.Result { + if meta.VersionMajor >= 7 && meta.VersionMinor >= 4 { + m = append(m, prometheus.MustNewConstMetric(Priority, prometheus.GaugeValue, r.Priority, r.Serial, strconv.FormatInt(r.Vcluster, 10), r.Hostname, strconv.FormatBool(r.Master), strconv.FormatBool(r.Primary))) + } else { + m = append(m, prometheus.MustNewConstMetric(Priority, prometheus.GaugeValue, r.Priority, r.Serial, strconv.FormatInt(r.Vcluster, 10), r.Hostname, strconv.FormatBool(r.Master), "Unsupported")) + } + } + return m, true +} \ No newline at end of file diff --git a/pkg/probe/system_ha_peer_test.go b/pkg/probe/system_ha_peer_test.go new file mode 100644 index 00000000..65c048ef --- /dev/null +++ b/pkg/probe/system_ha_peer_test.go @@ -0,0 +1,70 @@ +// Copyright 2025 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package probe + +import ( + "strings" + "testing" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/testutil" +) + +func TestSystemHaPeerOld(t *testing.T) { + c := newFakeClient() + c.prepare("api/v2/monitor/system/ha-peer", "testdata/system-ha-peer.jsonnet") + r := prometheus.NewPedanticRegistry() + meta := &TargetMetadata{ + VersionMajor: 7, + VersionMinor: 0, + } + if !testProbeWithMetadata(probeSystemHaPeer, c, meta, r) { + t.Errorf("probeSystemHaPeer() returned non-success") + } + + em := ` + # HELP fortigate_ha_peer_priority Priority level of the HA peer device. + # TYPE fortigate_ha_peer_priority gauge + fortigate_ha_peer_priority{hostname="member-name-1",master="false",primary="Unsupported",serial="FGT61E4QXXXXXXXX1",vcluster="0"} 200 + fortigate_ha_peer_priority{hostname="member-name-2",master="false",primary="Unsupported",serial="FGT61E4QXXXXXXXX2",vcluster="0"} 100 + ` + + if err := testutil.GatherAndCompare(r, strings.NewReader(em)); err != nil { + t.Fatalf("metric compare: err %v", err) + } +} + +func TestSystemHaPeerAfter74(t *testing.T) { + c := newFakeClient() + c.prepare("api/v2/monitor/system/ha-peer", "testdata/system-ha-peer.jsonnet") + r := prometheus.NewPedanticRegistry() + meta := &TargetMetadata{ + VersionMajor: 7, + VersionMinor: 4, + } + if !testProbeWithMetadata(probeSystemHaPeer, c, meta, r) { + t.Errorf("probeSystemHaPeer() returned non-success") + } + + em := ` + # HELP fortigate_ha_peer_priority Priority level of the HA peer device. + # TYPE fortigate_ha_peer_priority gauge + fortigate_ha_peer_priority{hostname="member-name-1",master="false",primary="true",serial="FGT61E4QXXXXXXXX1",vcluster="0"} 200 + fortigate_ha_peer_priority{hostname="member-name-2",master="false",primary="false",serial="FGT61E4QXXXXXXXX2",vcluster="0"} 100 + ` + + if err := testutil.GatherAndCompare(r, strings.NewReader(em)); err != nil { + t.Fatalf("metric compare: err %v", err) + } +} \ No newline at end of file diff --git a/pkg/probe/testdata/system-ha-peer.jsonnet b/pkg/probe/testdata/system-ha-peer.jsonnet new file mode 100644 index 00000000..a9828bb7 --- /dev/null +++ b/pkg/probe/testdata/system-ha-peer.jsonnet @@ -0,0 +1,27 @@ +# api/v2/monitor/system/ha-peer +{ + "http_method":"GET", + "results":[ + { + "serial_no":"FGT61E4QXXXXXXXX1", + "vcluster_id":0, + "priority":200, + "hostname":"member-name-1", + "primary":true + }, + { + "serial_no":"FGT61E4QXXXXXXXX2", + "vcluster_id":0, + "priority":100, + "hostname":"member-name-2" + } + ], + "vdom":"root", + "path":"system", + "name":"ha-peer", + "action":"", + "status":"success", + "serial":"FGT61E4QXXXXXXXX1", + "version":"v7.4.0", + "build":700 +} \ No newline at end of file From a070fe70d867822cb0444641f9a0cc26063ce27f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96rnfeldt=20Philip=20=2866140321=29?= Date: Tue, 7 Oct 2025 13:42:39 +0200 Subject: [PATCH 2/7] Corrected data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Örnfeldt Philip (66140321) --- pkg/probe/system_ha_peer.go | 15 ++++++++++----- pkg/probe/system_ha_peer_test.go | 15 +++++++-------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/pkg/probe/system_ha_peer.go b/pkg/probe/system_ha_peer.go index ce268452..68ef85ca 100644 --- a/pkg/probe/system_ha_peer.go +++ b/pkg/probe/system_ha_peer.go @@ -24,9 +24,9 @@ import ( func probeSystemHaPeer (c http.FortiHTTP, meta *TargetMetadata) ([]prometheus.Metric, bool) { var ( Priority = prometheus.NewDesc( - "fortigate_ha_peer_priority", - "Priority level of the HA peer device.", - []string{"serial","vcluster","hostname","master","primary"}, nil, + "fortigate_ha_peer", + "True when the peer device is the HA primary.(true=1, false=0)", + []string{"serial","vcluster","hostname","master","primary","priority"}, nil, ) ) @@ -51,9 +51,14 @@ func probeSystemHaPeer (c http.FortiHTTP, meta *TargetMetadata) ([]prometheus.Me m := []prometheus.Metric{} for _, r := range res.Result { if meta.VersionMajor >= 7 && meta.VersionMinor >= 4 { - m = append(m, prometheus.MustNewConstMetric(Priority, prometheus.GaugeValue, r.Priority, r.Serial, strconv.FormatInt(r.Vcluster, 10), r.Hostname, strconv.FormatBool(r.Master), strconv.FormatBool(r.Primary))) + if (r.Primary) { + m = append(m, prometheus.MustNewConstMetric(Priority, prometheus.GaugeValue, 1, r.Serial, strconv.FormatInt(r.Vcluster, 10), r.Hostname, strconv.FormatBool(r.Master), strconv.FormatBool(r.Primary), strconv.FormatFloat(r.Priority, 'f', -1, 64))) + } else { + m = append(m, prometheus.MustNewConstMetric(Priority, prometheus.GaugeValue, 0, r.Serial, strconv.FormatInt(r.Vcluster, 10), r.Hostname, strconv.FormatBool(r.Master), strconv.FormatBool(r.Primary), strconv.FormatFloat(r.Priority, 'f', -1, 64))) + } } else { - m = append(m, prometheus.MustNewConstMetric(Priority, prometheus.GaugeValue, r.Priority, r.Serial, strconv.FormatInt(r.Vcluster, 10), r.Hostname, strconv.FormatBool(r.Master), "Unsupported")) + m = append(m, prometheus.MustNewConstMetric(Priority, prometheus.GaugeValue, -1, "None", "0", "None", "false", "Unsupported", "false")) + break } } return m, true diff --git a/pkg/probe/system_ha_peer_test.go b/pkg/probe/system_ha_peer_test.go index 65c048ef..a59c95dd 100644 --- a/pkg/probe/system_ha_peer_test.go +++ b/pkg/probe/system_ha_peer_test.go @@ -34,10 +34,9 @@ func TestSystemHaPeerOld(t *testing.T) { } em := ` - # HELP fortigate_ha_peer_priority Priority level of the HA peer device. - # TYPE fortigate_ha_peer_priority gauge - fortigate_ha_peer_priority{hostname="member-name-1",master="false",primary="Unsupported",serial="FGT61E4QXXXXXXXX1",vcluster="0"} 200 - fortigate_ha_peer_priority{hostname="member-name-2",master="false",primary="Unsupported",serial="FGT61E4QXXXXXXXX2",vcluster="0"} 100 + # HELP fortigate_ha_peer True when the peer device is the HA primary.(true=1, false=0) + # TYPE fortigate_ha_peer gauge + fortigate_ha_peer{hostname="None",master="false",primary="Unsupported",priority="false",serial="None",vcluster="0"} -1 ` if err := testutil.GatherAndCompare(r, strings.NewReader(em)); err != nil { @@ -58,10 +57,10 @@ func TestSystemHaPeerAfter74(t *testing.T) { } em := ` - # HELP fortigate_ha_peer_priority Priority level of the HA peer device. - # TYPE fortigate_ha_peer_priority gauge - fortigate_ha_peer_priority{hostname="member-name-1",master="false",primary="true",serial="FGT61E4QXXXXXXXX1",vcluster="0"} 200 - fortigate_ha_peer_priority{hostname="member-name-2",master="false",primary="false",serial="FGT61E4QXXXXXXXX2",vcluster="0"} 100 + # HELP fortigate_ha_peer True when the peer device is the HA primary.(true=1, false=0) + # TYPE fortigate_ha_peer gauge + fortigate_ha_peer{hostname="member-name-1",master="false",primary="true",priority="200",serial="FGT61E4QXXXXXXXX1",vcluster="0"} 1 + fortigate_ha_peer{hostname="member-name-2",master="false",primary="false",priority="100",serial="FGT61E4QXXXXXXXX2",vcluster="0"} 0 ` if err := testutil.GatherAndCompare(r, strings.NewReader(em)); err != nil { From d57c67851aaebb333841c6dce4b9cf0e0566188f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96rnfeldt=20Philip=20=2866140321=29?= Date: Wed, 12 Nov 2025 14:17:08 +0100 Subject: [PATCH 3/7] Correct state metrics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Örnfeldt Philip (66140321) --- pkg/probe/system_ha_peer.go | 8 +++++--- pkg/probe/system_ha_peer_test.go | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/pkg/probe/system_ha_peer.go b/pkg/probe/system_ha_peer.go index 68ef85ca..e74539eb 100644 --- a/pkg/probe/system_ha_peer.go +++ b/pkg/probe/system_ha_peer.go @@ -25,7 +25,7 @@ func probeSystemHaPeer (c http.FortiHTTP, meta *TargetMetadata) ([]prometheus.Me var ( Priority = prometheus.NewDesc( "fortigate_ha_peer", - "True when the peer device is the HA primary.(true=1, false=0)", + "True when the peer device is the HA primary.", []string{"serial","vcluster","hostname","master","primary","priority"}, nil, ) ) @@ -52,9 +52,11 @@ func probeSystemHaPeer (c http.FortiHTTP, meta *TargetMetadata) ([]prometheus.Me for _, r := range res.Result { if meta.VersionMajor >= 7 && meta.VersionMinor >= 4 { if (r.Primary) { - m = append(m, prometheus.MustNewConstMetric(Priority, prometheus.GaugeValue, 1, r.Serial, strconv.FormatInt(r.Vcluster, 10), r.Hostname, strconv.FormatBool(r.Master), strconv.FormatBool(r.Primary), strconv.FormatFloat(r.Priority, 'f', -1, 64))) + m = append(m, prometheus.MustNewConstMetric(Priority, prometheus.GaugeValue, 1, r.Serial, strconv.FormatInt(r.Vcluster, 10), r.Hostname, strconv.FormatBool(r.Master), "true", strconv.FormatFloat(r.Priority, 'f', -1, 64))) + m = append(m, prometheus.MustNewConstMetric(Priority, prometheus.GaugeValue, 0, r.Serial, strconv.FormatInt(r.Vcluster, 10), r.Hostname, strconv.FormatBool(r.Master), "false", strconv.FormatFloat(r.Priority, 'f', -1, 64))) } else { - m = append(m, prometheus.MustNewConstMetric(Priority, prometheus.GaugeValue, 0, r.Serial, strconv.FormatInt(r.Vcluster, 10), r.Hostname, strconv.FormatBool(r.Master), strconv.FormatBool(r.Primary), strconv.FormatFloat(r.Priority, 'f', -1, 64))) + m = append(m, prometheus.MustNewConstMetric(Priority, prometheus.GaugeValue, 0, r.Serial, strconv.FormatInt(r.Vcluster, 10), r.Hostname, strconv.FormatBool(r.Master), "true", strconv.FormatFloat(r.Priority, 'f', -1, 64))) + m = append(m, prometheus.MustNewConstMetric(Priority, prometheus.GaugeValue, 1, r.Serial, strconv.FormatInt(r.Vcluster, 10), r.Hostname, strconv.FormatBool(r.Master), "false", strconv.FormatFloat(r.Priority, 'f', -1, 64))) } } else { m = append(m, prometheus.MustNewConstMetric(Priority, prometheus.GaugeValue, -1, "None", "0", "None", "false", "Unsupported", "false")) diff --git a/pkg/probe/system_ha_peer_test.go b/pkg/probe/system_ha_peer_test.go index a59c95dd..89444a42 100644 --- a/pkg/probe/system_ha_peer_test.go +++ b/pkg/probe/system_ha_peer_test.go @@ -34,7 +34,7 @@ func TestSystemHaPeerOld(t *testing.T) { } em := ` - # HELP fortigate_ha_peer True when the peer device is the HA primary.(true=1, false=0) + # HELP fortigate_ha_peer True when the peer device is the HA primary. # TYPE fortigate_ha_peer gauge fortigate_ha_peer{hostname="None",master="false",primary="Unsupported",priority="false",serial="None",vcluster="0"} -1 ` @@ -57,10 +57,12 @@ func TestSystemHaPeerAfter74(t *testing.T) { } em := ` - # HELP fortigate_ha_peer True when the peer device is the HA primary.(true=1, false=0) + # HELP fortigate_ha_peer True when the peer device is the HA primary. # TYPE fortigate_ha_peer gauge + fortigate_ha_peer{hostname="member-name-1",master="false",primary="false",priority="200",serial="FGT61E4QXXXXXXXX1",vcluster="0"} 0 fortigate_ha_peer{hostname="member-name-1",master="false",primary="true",priority="200",serial="FGT61E4QXXXXXXXX1",vcluster="0"} 1 - fortigate_ha_peer{hostname="member-name-2",master="false",primary="false",priority="100",serial="FGT61E4QXXXXXXXX2",vcluster="0"} 0 + fortigate_ha_peer{hostname="member-name-2",master="false",primary="false",priority="100",serial="FGT61E4QXXXXXXXX2",vcluster="0"} 1 + fortigate_ha_peer{hostname="member-name-2",master="false",primary="true",priority="100",serial="FGT61E4QXXXXXXXX2",vcluster="0"} 0 ` if err := testutil.GatherAndCompare(r, strings.NewReader(em)); err != nil { From 407697647c86f8f85045c25c499fd7a6a1bcc007 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96rnfeldt=20Philip=20=2866140321=29?= Date: Thu, 13 Nov 2025 20:20:32 +0100 Subject: [PATCH 4/7] Lint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Örnfeldt Philip (66140321) --- pkg/probe/probe.go | 2 +- pkg/probe/system_ha_peer.go | 27 ++++++------- pkg/probe/system_ha_peer_test.go | 2 +- pkg/probe/system_vdom-resource.go | 66 +++++++++++++++---------------- 4 files changed, 48 insertions(+), 49 deletions(-) diff --git a/pkg/probe/probe.go b/pkg/probe/probe.go index 45e72d68..2ca73734 100644 --- a/pkg/probe/probe.go +++ b/pkg/probe/probe.go @@ -156,7 +156,7 @@ func (p *Collector) Probe(ctx context.Context, target map[string]string, hc *htt {"System/SDNConnector", probeSystemSDNConnector}, {"System/SensorInfo", probeSystemSensorInfo}, {"System/Status", probeSystemStatus}, - {"System/VDOMResource",probeSystemVdomResource}, + {"System/VDOMResource", probeSystemVdomResource}, {"System/HAChecksum", probeSystemHAChecksum}, {"User/Fsso", probeUserFsso}, {"VPN/IPSec", probeVPNIPSec}, diff --git a/pkg/probe/system_ha_peer.go b/pkg/probe/system_ha_peer.go index e74539eb..37bb27cb 100644 --- a/pkg/probe/system_ha_peer.go +++ b/pkg/probe/system_ha_peer.go @@ -17,28 +17,27 @@ import ( "log" "strconv" - "github.com/prometheus-community/fortigate_exporter/pkg/http" "github.com/prometheus/client_golang/prometheus" + + "github.com/prometheus-community/fortigate_exporter/pkg/http" ) -func probeSystemHaPeer (c http.FortiHTTP, meta *TargetMetadata) ([]prometheus.Metric, bool) { - var ( - Priority = prometheus.NewDesc( - "fortigate_ha_peer", - "True when the peer device is the HA primary.", - []string{"serial","vcluster","hostname","master","primary","priority"}, nil, - ) +func probeSystemHaPeer(c http.FortiHTTP, meta *TargetMetadata) ([]prometheus.Metric, bool) { + Priority := prometheus.NewDesc( + "fortigate_ha_peer", + "True when the peer device is the HA primary.", + []string{"serial", "vcluster", "hostname", "master", "primary", "priority"}, nil, ) type SystemHaPeer struct { Serial string `json:"serial_no"` - Vcluster int64 `json:"vcluster_id"` + Vcluster int64 `json:"vcluster_id"` Priority float64 `json:"priority"` Hostname string `json:"hostname"` - Master bool `json:"master"` - Primary bool `json:"primary"` + Master bool `json:"master"` + Primary bool `json:"primary"` } - + type SystemHaPeerResult struct { Result []SystemHaPeer `json:"results"` } @@ -51,7 +50,7 @@ func probeSystemHaPeer (c http.FortiHTTP, meta *TargetMetadata) ([]prometheus.Me m := []prometheus.Metric{} for _, r := range res.Result { if meta.VersionMajor >= 7 && meta.VersionMinor >= 4 { - if (r.Primary) { + if r.Primary { m = append(m, prometheus.MustNewConstMetric(Priority, prometheus.GaugeValue, 1, r.Serial, strconv.FormatInt(r.Vcluster, 10), r.Hostname, strconv.FormatBool(r.Master), "true", strconv.FormatFloat(r.Priority, 'f', -1, 64))) m = append(m, prometheus.MustNewConstMetric(Priority, prometheus.GaugeValue, 0, r.Serial, strconv.FormatInt(r.Vcluster, 10), r.Hostname, strconv.FormatBool(r.Master), "false", strconv.FormatFloat(r.Priority, 'f', -1, 64))) } else { @@ -64,4 +63,4 @@ func probeSystemHaPeer (c http.FortiHTTP, meta *TargetMetadata) ([]prometheus.Me } } return m, true -} \ No newline at end of file +} diff --git a/pkg/probe/system_ha_peer_test.go b/pkg/probe/system_ha_peer_test.go index 89444a42..2666a7e7 100644 --- a/pkg/probe/system_ha_peer_test.go +++ b/pkg/probe/system_ha_peer_test.go @@ -68,4 +68,4 @@ func TestSystemHaPeerAfter74(t *testing.T) { if err := testutil.GatherAndCompare(r, strings.NewReader(em)); err != nil { t.Fatalf("metric compare: err %v", err) } -} \ No newline at end of file +} diff --git a/pkg/probe/system_vdom-resource.go b/pkg/probe/system_vdom-resource.go index c955a61a..a37e76c9 100644 --- a/pkg/probe/system_vdom-resource.go +++ b/pkg/probe/system_vdom-resource.go @@ -16,12 +16,12 @@ package probe import ( "log" - "github.com/prometheus-community/fortigate_exporter/pkg/http" "github.com/prometheus/client_golang/prometheus" + + "github.com/prometheus-community/fortigate_exporter/pkg/http" ) -func probeSystemVdomResource(c http.FortiHTTP, meta *TargetMetadata) ([]prometheus.Metric, bool) { - +func probeSystemVdomResource(c http.FortiHTTP, _ *TargetMetadata) ([]prometheus.Metric, bool) { vdomDesc := make(map[string]*prometheus.Desc) vdomDesc["cpu"] = prometheus.NewDesc( "fortigate_vdom_resource_cpu_usage_ratio", @@ -46,12 +46,12 @@ func probeSystemVdomResource(c http.FortiHTTP, meta *TargetMetadata) ([]promethe vdomDesc["id"] = prometheus.NewDesc( "fortigate_vdom_resource_object_id", "Object Resource ID", - []string{"vdom", "object"},nil, + []string{"vdom", "object"}, nil, ) vdomDesc["custom_max"] = prometheus.NewDesc( "fortigate_vdom_resource_object_custom_max", "Object Custom Max", - []string{"vdom", "object"},nil, + []string{"vdom", "object"}, nil, ) vdomDesc["min_custom_value"] = prometheus.NewDesc( "fortigate_vdom_resource_object_custom_min_value", @@ -61,42 +61,42 @@ func probeSystemVdomResource(c http.FortiHTTP, meta *TargetMetadata) ([]promethe vdomDesc["max_custom_value"] = prometheus.NewDesc( "fortigate_vdom_resource_object_custom_max_value", "Object Maximum custom value", - []string{"vdom", "object"},nil, + []string{"vdom", "object"}, nil, ) vdomDesc["guaranteed"] = prometheus.NewDesc( "fortigate_vdom_resource_object_guaranteed", "Object Guaranteed", - []string{"vdom", "object"},nil, + []string{"vdom", "object"}, nil, ) vdomDesc["min_guaranteed_value"] = prometheus.NewDesc( "fortigate_vdom_resource_object_guaranteed_max_value", "Object Minimum guaranteed value", - []string{"vdom", "object"},nil, + []string{"vdom", "object"}, nil, ) vdomDesc["max_guaranteed_value"] = prometheus.NewDesc( "fortigate_vdom_resource_object_guaranteed_min_value", "Object Maximum guaranteed value", - []string{"vdom", "object"},nil, + []string{"vdom", "object"}, nil, ) vdomDesc["global_max"] = prometheus.NewDesc( "fortigate_vdom_resource_object_global_max", "Object Global max", - []string{"vdom", "object"},nil, + []string{"vdom", "object"}, nil, ) vdomDesc["current_usage"] = prometheus.NewDesc( "fortigate_vdom_resource_object_current_usage", "Object Current usage", - []string{"vdom", "object"},nil, + []string{"vdom", "object"}, nil, ) vdomDesc["usage_percent"] = prometheus.NewDesc( "fortigate_vdom_resource_object_usage_ratio", "Object Usage percentage", - []string{"vdom", "object"},nil, + []string{"vdom", "object"}, nil, ) type VDOMResourceResult struct { - Result interface{} `json:"results"` - Vdom string `json:"vdom"` + Result any `json:"results"` + Vdom string `json:"vdom"` } var res []VDOMResourceResult @@ -107,7 +107,7 @@ func probeSystemVdomResource(c http.FortiHTTP, meta *TargetMetadata) ([]promethe m := []prometheus.Metric{} for _, result := range res { - for k, elem := range result.Result.(map[string]interface{}) { + for k, elem := range result.Result.(map[string]any) { switch k { case "cpu", "memory", "setup_rate": m = append(m, prometheus.MustNewConstMetric(vdomDesc[k], prometheus.GaugeValue, elem.(float64), result.Vdom)) @@ -118,24 +118,24 @@ func probeSystemVdomResource(c http.FortiHTTP, meta *TargetMetadata) ([]promethe m = append(m, prometheus.MustNewConstMetric(vdomDesc[k], prometheus.GaugeValue, 0, result.Vdom)) } case "session", - "ipsec-phase1", - "ipsec-phase2", - "ipsec-phase1-interface", - "ipsec-phase2-interface", - "dialup-tunnel", - "firewall-policy", - "firewall-address", - "firewall-addrgrp", - "custom-service", - "service-group", - "onetime-schedule", - "recurring-schedule", - "user", - "user-group", - "sslvpn", - "proxy", - "log-disk-quota": - for val, e := range elem.(map[string]interface{}) { + "ipsec-phase1", + "ipsec-phase2", + "ipsec-phase1-interface", + "ipsec-phase2-interface", + "dialup-tunnel", + "firewall-policy", + "firewall-address", + "firewall-addrgrp", + "custom-service", + "service-group", + "onetime-schedule", + "recurring-schedule", + "user", + "user-group", + "sslvpn", + "proxy", + "log-disk-quota": + for val, e := range elem.(map[string]any) { m = append(m, prometheus.MustNewConstMetric(vdomDesc[val], prometheus.GaugeValue, e.(float64), result.Vdom, k)) } default: From 404c0d57a7f2daea132a2aadd7d06a1c14cba017 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96rnfeldt=20Philip=20=2866140321=29?= Date: Wed, 19 Nov 2025 11:03:26 +0100 Subject: [PATCH 5/7] New metrics for ha peer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Örnfeldt Philip (66140321) --- pkg/probe/system_ha_peer.go | 21 +++++++++++++-------- pkg/probe/system_ha_peer_test.go | 20 +++++++++++--------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/pkg/probe/system_ha_peer.go b/pkg/probe/system_ha_peer.go index 37bb27cb..f174816e 100644 --- a/pkg/probe/system_ha_peer.go +++ b/pkg/probe/system_ha_peer.go @@ -23,10 +23,16 @@ import ( ) func probeSystemHaPeer(c http.FortiHTTP, meta *TargetMetadata) ([]prometheus.Metric, bool) { - Priority := prometheus.NewDesc( - "fortigate_ha_peer", + Info := prometheus.NewDesc( + "fortigate_ha_peer_info", + "Information about the ha peer.", + []string{"serial", "vcluster", "hostname", "priority"}, nil, + ) + + Primary := prometheus.NewDesc( + "fortigate_ha_peer_primary", "True when the peer device is the HA primary.", - []string{"serial", "vcluster", "hostname", "master", "primary", "priority"}, nil, + []string{"vcluster", "hostname"}, nil, ) type SystemHaPeer struct { @@ -50,15 +56,14 @@ func probeSystemHaPeer(c http.FortiHTTP, meta *TargetMetadata) ([]prometheus.Met m := []prometheus.Metric{} for _, r := range res.Result { if meta.VersionMajor >= 7 && meta.VersionMinor >= 4 { + 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))) if r.Primary { - m = append(m, prometheus.MustNewConstMetric(Priority, prometheus.GaugeValue, 1, r.Serial, strconv.FormatInt(r.Vcluster, 10), r.Hostname, strconv.FormatBool(r.Master), "true", strconv.FormatFloat(r.Priority, 'f', -1, 64))) - m = append(m, prometheus.MustNewConstMetric(Priority, prometheus.GaugeValue, 0, r.Serial, strconv.FormatInt(r.Vcluster, 10), r.Hostname, strconv.FormatBool(r.Master), "false", strconv.FormatFloat(r.Priority, 'f', -1, 64))) + m = append(m, prometheus.MustNewConstMetric(Primary, prometheus.GaugeValue, 1, strconv.FormatInt(r.Vcluster, 10), r.Hostname)) } else { - m = append(m, prometheus.MustNewConstMetric(Priority, prometheus.GaugeValue, 0, r.Serial, strconv.FormatInt(r.Vcluster, 10), r.Hostname, strconv.FormatBool(r.Master), "true", strconv.FormatFloat(r.Priority, 'f', -1, 64))) - m = append(m, prometheus.MustNewConstMetric(Priority, prometheus.GaugeValue, 1, r.Serial, strconv.FormatInt(r.Vcluster, 10), r.Hostname, strconv.FormatBool(r.Master), "false", strconv.FormatFloat(r.Priority, 'f', -1, 64))) + m = append(m, prometheus.MustNewConstMetric(Primary, prometheus.GaugeValue, 0, strconv.FormatInt(r.Vcluster, 10), r.Hostname)) } } else { - m = append(m, prometheus.MustNewConstMetric(Priority, prometheus.GaugeValue, -1, "None", "0", "None", "false", "Unsupported", "false")) + m = append(m, prometheus.MustNewConstMetric(Info, prometheus.GaugeValue, -1, "None", "0", "None", "false")) break } } diff --git a/pkg/probe/system_ha_peer_test.go b/pkg/probe/system_ha_peer_test.go index 2666a7e7..f0f00d03 100644 --- a/pkg/probe/system_ha_peer_test.go +++ b/pkg/probe/system_ha_peer_test.go @@ -34,9 +34,9 @@ func TestSystemHaPeerOld(t *testing.T) { } em := ` - # HELP fortigate_ha_peer True when the peer device is the HA primary. - # TYPE fortigate_ha_peer gauge - fortigate_ha_peer{hostname="None",master="false",primary="Unsupported",priority="false",serial="None",vcluster="0"} -1 + # HELP fortigate_ha_peer_info Information about the ha peer. + # TYPE fortigate_ha_peer_info gauge + fortigate_ha_peer_info{hostname="None",priority="false",serial="None",vcluster="0"} -1 ` if err := testutil.GatherAndCompare(r, strings.NewReader(em)); err != nil { @@ -57,12 +57,14 @@ func TestSystemHaPeerAfter74(t *testing.T) { } em := ` - # HELP fortigate_ha_peer True when the peer device is the HA primary. - # TYPE fortigate_ha_peer gauge - fortigate_ha_peer{hostname="member-name-1",master="false",primary="false",priority="200",serial="FGT61E4QXXXXXXXX1",vcluster="0"} 0 - fortigate_ha_peer{hostname="member-name-1",master="false",primary="true",priority="200",serial="FGT61E4QXXXXXXXX1",vcluster="0"} 1 - fortigate_ha_peer{hostname="member-name-2",master="false",primary="false",priority="100",serial="FGT61E4QXXXXXXXX2",vcluster="0"} 1 - fortigate_ha_peer{hostname="member-name-2",master="false",primary="true",priority="100",serial="FGT61E4QXXXXXXXX2",vcluster="0"} 0 + # HELP fortigate_ha_peer_info Information about the ha peer. + # TYPE fortigate_ha_peer_info gauge + fortigate_ha_peer_info{hostname="member-name-1",priority="200",serial="FGT61E4QXXXXXXXX1",vcluster="0"} 1 + fortigate_ha_peer_info{hostname="member-name-2",priority="100",serial="FGT61E4QXXXXXXXX2",vcluster="0"} 1 + # HELP fortigate_ha_peer_primary True when the peer device is the HA primary. + # TYPE fortigate_ha_peer_primary gauge + fortigate_ha_peer_primary{hostname="member-name-1",vcluster="0"} 1 + fortigate_ha_peer_primary{hostname="member-name-2",vcluster="0"} 0 ` if err := testutil.GatherAndCompare(r, strings.NewReader(em)); err != nil { From 55df8e441c813d8e5340a4e382491f1dc12a750c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96rnfeldt=20Philip=20=2866140321=29?= Date: Fri, 21 Nov 2025 20:39:07 +0100 Subject: [PATCH 6/7] Removed year in copyright, removed public variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Örnfeldt Philip (66140321) --- metrics.md | 3 ++- pkg/probe/system_ha_peer.go | 14 +++++++------- pkg/probe/system_ha_peer_test.go | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/metrics.md b/metrics.md index 63e2431b..4bf334c8 100644 --- a/metrics.md +++ b/metrics.md @@ -38,7 +38,8 @@ Global: * _System/HAChecksums_ * `fortigate_ha_member_has_role` * _System/HAPeer_ - * `fortigate_ha_peer` + * `fortigate_ha_peer_info` + * `fortigate_ha_peer_primary` * _System/Ntp/Status_ * `fortigate_system_ntp_delay_seconds` * `fortigate_system_ntp_dispersion_seconds` diff --git a/pkg/probe/system_ha_peer.go b/pkg/probe/system_ha_peer.go index f174816e..45a1302c 100644 --- a/pkg/probe/system_ha_peer.go +++ b/pkg/probe/system_ha_peer.go @@ -1,4 +1,4 @@ -// Copyright 2025 The Prometheus Authors +// Copyright The Prometheus Authors // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at @@ -23,13 +23,13 @@ import ( ) func probeSystemHaPeer(c http.FortiHTTP, meta *TargetMetadata) ([]prometheus.Metric, bool) { - Info := prometheus.NewDesc( + info := prometheus.NewDesc( "fortigate_ha_peer_info", "Information about the ha peer.", []string{"serial", "vcluster", "hostname", "priority"}, nil, ) - Primary := prometheus.NewDesc( + primary := prometheus.NewDesc( "fortigate_ha_peer_primary", "True when the peer device is the HA primary.", []string{"vcluster", "hostname"}, nil, @@ -56,14 +56,14 @@ func probeSystemHaPeer(c http.FortiHTTP, meta *TargetMetadata) ([]prometheus.Met m := []prometheus.Metric{} for _, r := range res.Result { if meta.VersionMajor >= 7 && meta.VersionMinor >= 4 { - 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))) + 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))) if r.Primary { - m = append(m, prometheus.MustNewConstMetric(Primary, prometheus.GaugeValue, 1, strconv.FormatInt(r.Vcluster, 10), r.Hostname)) + m = append(m, prometheus.MustNewConstMetric(primary, prometheus.GaugeValue, 1, strconv.FormatInt(r.Vcluster, 10), r.Hostname)) } else { - m = append(m, prometheus.MustNewConstMetric(Primary, prometheus.GaugeValue, 0, strconv.FormatInt(r.Vcluster, 10), r.Hostname)) + m = append(m, prometheus.MustNewConstMetric(primary, prometheus.GaugeValue, 0, strconv.FormatInt(r.Vcluster, 10), r.Hostname)) } } else { - m = append(m, prometheus.MustNewConstMetric(Info, prometheus.GaugeValue, -1, "None", "0", "None", "false")) + m = append(m, prometheus.MustNewConstMetric(info, prometheus.GaugeValue, -1, "None", "0", "None", "false")) break } } diff --git a/pkg/probe/system_ha_peer_test.go b/pkg/probe/system_ha_peer_test.go index f0f00d03..8a6e2d26 100644 --- a/pkg/probe/system_ha_peer_test.go +++ b/pkg/probe/system_ha_peer_test.go @@ -1,4 +1,4 @@ -// Copyright 2025 The Prometheus Authors +// Copyright The Prometheus Authors // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at From 298cea8badcd135e27e090a2a5afe04fd5de63e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96rnfeldt=20Philip=20=2866140321=29?= Date: Mon, 24 Nov 2025 13:20:56 +0100 Subject: [PATCH 7/7] Added master back if minor version is equal to 4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Örnfeldt Philip (66140321) --- pkg/probe/system_ha_peer.go | 13 +++++++++++++ pkg/probe/system_ha_peer_test.go | 4 ++++ pkg/probe/testdata/system-ha-peer.jsonnet | 3 ++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/pkg/probe/system_ha_peer.go b/pkg/probe/system_ha_peer.go index 45a1302c..588bccdd 100644 --- a/pkg/probe/system_ha_peer.go +++ b/pkg/probe/system_ha_peer.go @@ -35,6 +35,12 @@ func probeSystemHaPeer(c http.FortiHTTP, meta *TargetMetadata) ([]prometheus.Met []string{"vcluster", "hostname"}, nil, ) + master := prometheus.NewDesc( + "fortigate_ha_peer_master", + "True when the peer device is the HA master.", + []string{"vcluster", "hostname"}, nil, + ) + type SystemHaPeer struct { Serial string `json:"serial_no"` Vcluster int64 `json:"vcluster_id"` @@ -62,6 +68,13 @@ func probeSystemHaPeer(c http.FortiHTTP, meta *TargetMetadata) ([]prometheus.Met } else { m = append(m, prometheus.MustNewConstMetric(primary, prometheus.GaugeValue, 0, strconv.FormatInt(r.Vcluster, 10), r.Hostname)) } + if meta.VersionMinor == 4 { + if r.Master { + m = append(m, prometheus.MustNewConstMetric(master, prometheus.GaugeValue, 1, strconv.FormatInt(r.Vcluster, 10), r.Hostname)) + } else { + m = append(m, prometheus.MustNewConstMetric(master, prometheus.GaugeValue, 0, strconv.FormatInt(r.Vcluster, 10), r.Hostname)) + } + } } else { m = append(m, prometheus.MustNewConstMetric(info, prometheus.GaugeValue, -1, "None", "0", "None", "false")) break diff --git a/pkg/probe/system_ha_peer_test.go b/pkg/probe/system_ha_peer_test.go index 8a6e2d26..34769876 100644 --- a/pkg/probe/system_ha_peer_test.go +++ b/pkg/probe/system_ha_peer_test.go @@ -61,6 +61,10 @@ func TestSystemHaPeerAfter74(t *testing.T) { # TYPE fortigate_ha_peer_info gauge fortigate_ha_peer_info{hostname="member-name-1",priority="200",serial="FGT61E4QXXXXXXXX1",vcluster="0"} 1 fortigate_ha_peer_info{hostname="member-name-2",priority="100",serial="FGT61E4QXXXXXXXX2",vcluster="0"} 1 + # HELP fortigate_ha_peer_master True when the peer device is the HA master. + # TYPE fortigate_ha_peer_master gauge + fortigate_ha_peer_master{hostname="member-name-1",vcluster="0"} 0 + fortigate_ha_peer_master{hostname="member-name-2",vcluster="0"} 1 # HELP fortigate_ha_peer_primary True when the peer device is the HA primary. # TYPE fortigate_ha_peer_primary gauge fortigate_ha_peer_primary{hostname="member-name-1",vcluster="0"} 1 diff --git a/pkg/probe/testdata/system-ha-peer.jsonnet b/pkg/probe/testdata/system-ha-peer.jsonnet index a9828bb7..5d081a07 100644 --- a/pkg/probe/testdata/system-ha-peer.jsonnet +++ b/pkg/probe/testdata/system-ha-peer.jsonnet @@ -13,7 +13,8 @@ "serial_no":"FGT61E4QXXXXXXXX2", "vcluster_id":0, "priority":100, - "hostname":"member-name-2" + "hostname":"member-name-2", + "master": true } ], "vdom":"root",