From 3ce249d405f277dc74154a28343a823282b19305 Mon Sep 17 00:00:00 2001 From: Joel Norberg Date: Fri, 11 Oct 2024 15:05:34 +0200 Subject: [PATCH 1/2] [feat] HA Peer status metric --- README.md | 2 + pkg/probe/probe.go | 1 + pkg/probe/system_ha_peer.go | 55 +++++++++++++++++++++++++ pkg/probe/system_ha_peer_test.go | 57 ++++++++++++++++++++++++++ pkg/probe/testdata/ha-peer-74+.jsonnet | 27 ++++++++++++ pkg/probe/testdata/ha-peer.jsonnet | 26 ++++++++++++ 6 files changed, 168 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/ha-peer-74+.jsonnet create mode 100644 pkg/probe/testdata/ha-peer.jsonnet diff --git a/README.md b/README.md index 82a0118b..67933b27 100755 --- a/README.md +++ b/README.md @@ -51,6 +51,8 @@ Global: * _WebUI/State_ * `fortigate_last_reboot_seconds` * `fortigate_last_snapshot_seconds` + * _System/HAPeerStatus_ + * `fortigate_ha_member_info` Per-VDOM: diff --git a/pkg/probe/probe.go b/pkg/probe/probe.go index c79a7f6f..3cacfb00 100644 --- a/pkg/probe/probe.go +++ b/pkg/probe/probe.go @@ -149,6 +149,7 @@ func (p *ProbeCollector) Probe(ctx context.Context, target map[string]string, hc {"Wifi/ManagedAP", probeWifiManagedAP}, {"Switch/ManagedSwitch", probeManagedSwitch}, {"OSPF/Neighbors", probeOSPFNeighbors}, + {"System/HAPeer", probeSystemHAPeer}, } { wanted := false diff --git a/pkg/probe/system_ha_peer.go b/pkg/probe/system_ha_peer.go new file mode 100644 index 00000000..7af77bd6 --- /dev/null +++ b/pkg/probe/system_ha_peer.go @@ -0,0 +1,55 @@ +package probe + +import ( + "log" + "strconv" + + "github.com/bluecmd/fortigate_exporter/pkg/http" + "github.com/prometheus/client_golang/prometheus" +) + +func probeSystemHAPeer(c http.FortiHTTP, meta *TargetMetadata) ([]prometheus.Metric, bool) { + var ( + memberInfo = prometheus.NewDesc( + "fortigate_ha_member_info", + "Info metrics regarding cluster HA peers", + []string{"vdom", "hostname", "serial", "priority", "vcluster_id", "primary"}, nil, + ) + ) + + type HAResults struct { + Hostname string `json:"hostname"` + SerialNo string `json:"serial_no"` + VclusterID int `json:"vcluster_id"` + Priority int `json:"priority"` + Primary bool `json:"primary"` // Set to true if primary node in FortiOS 7.4+ + } + + type HAResponse struct { + HTTPMethod string `json:"http_method"` + Results []HAResults `json:"results"` + VDOM string `json:"vdom"` + Path string `json:"path"` + Name string `json:"name"` + Status string `json:"status"` + Serial string `json:"serial"` + Version string `json:"version"` + Build int64 `json:"build"` + } + var r HAResponse + + if err := c.Get("api/v2/monitor/system/ha-peer", "", &r); err != nil { + log.Printf("Error: %v", err) + return nil, false + } + + m := []prometheus.Metric{} + for _, result := range r.Results { + strPrimary := strconv.FormatBool(result.Primary) + if meta.VersionMajor < 7 || (meta.VersionMajor == 7 && meta.VersionMinor < 4) { + strPrimary = "Unsupported" + } + m = append(m, prometheus.MustNewConstMetric(memberInfo, prometheus.GaugeValue, 1, r.VDOM, result.Hostname, result.SerialNo, strconv.Itoa(result.Priority), strconv.Itoa(result.VclusterID), strPrimary)) + } + return m, true +} diff --git a/pkg/probe/system_ha_peer_test.go b/pkg/probe/system_ha_peer_test.go new file mode 100644 index 00000000..cf7f2b0c --- /dev/null +++ b/pkg/probe/system_ha_peer_test.go @@ -0,0 +1,57 @@ +package probe + +import ( + "strings" + "testing" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/testutil" +) + +func TestHAPeer(t *testing.T) { + c := newFakeClient() + c.prepare("api/v2/monitor/system/ha-peer", "testdata/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_member_info Info metrics regarding cluster HA peers + # TYPE fortigate_ha_member_info gauge + fortigate_ha_member_info{hostname="member-name-1",primary="Unsupported",priority="200",serial="FGT61E4QXXXXXXXX1",vcluster_id="0",vdom="root"} 1 + fortigate_ha_member_info{hostname="member-name-2",primary="Unsupported",priority="100",serial="FGT61E4QXXXXXXXX2",vcluster_id="0",vdom="root"} 1 + ` + + if err := testutil.GatherAndCompare(r, strings.NewReader(em)); err != nil { + t.Fatalf("metric compare: err %v", err) + } +} + +func TestHAPeer74(t *testing.T) { + c := newFakeClient() + c.prepare("api/v2/monitor/system/ha-peer", "testdata/ha-peer-74+.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_member_info Info metrics regarding cluster HA peers + # TYPE fortigate_ha_member_info gauge + fortigate_ha_member_info{hostname="member-name-1",primary="true",priority="200",serial="FGT61E4QXXXXXXXX1",vcluster_id="0",vdom="root"} 1 + fortigate_ha_member_info{hostname="member-name-2",primary="false",priority="100",serial="FGT61E4QXXXXXXXX2",vcluster_id="0",vdom="root"} 1 + ` + + if err := testutil.GatherAndCompare(r, strings.NewReader(em)); err != nil { + t.Fatalf("metric compare: err %v", err) + } +} diff --git a/pkg/probe/testdata/ha-peer-74+.jsonnet b/pkg/probe/testdata/ha-peer-74+.jsonnet new file mode 100644 index 00000000..a9828bb7 --- /dev/null +++ b/pkg/probe/testdata/ha-peer-74+.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 diff --git a/pkg/probe/testdata/ha-peer.jsonnet b/pkg/probe/testdata/ha-peer.jsonnet new file mode 100644 index 00000000..0ebae689 --- /dev/null +++ b/pkg/probe/testdata/ha-peer.jsonnet @@ -0,0 +1,26 @@ +# api/v2/monitor/system/ha-peer +{ + "http_method":"GET", + "results":[ + { + "serial_no":"FGT61E4QXXXXXXXX1", + "vcluster_id":0, + "priority":200, + "hostname":"member-name-1" + }, + { + "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.0.12", + "build":523 +} \ No newline at end of file From 7de3bc191d94545bff1cb31d4e1acf5e7f86d56a Mon Sep 17 00:00:00 2001 From: Joel Norberg Date: Mon, 14 Oct 2024 12:15:57 +0200 Subject: [PATCH 2/2] [fix] corrected metric name --- pkg/probe/system_ha_peer.go | 2 +- pkg/probe/system_ha_peer_test.go | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pkg/probe/system_ha_peer.go b/pkg/probe/system_ha_peer.go index 7af77bd6..586039f1 100644 --- a/pkg/probe/system_ha_peer.go +++ b/pkg/probe/system_ha_peer.go @@ -11,7 +11,7 @@ import ( func probeSystemHAPeer(c http.FortiHTTP, meta *TargetMetadata) ([]prometheus.Metric, bool) { var ( memberInfo = prometheus.NewDesc( - "fortigate_ha_member_info", + "fortigate_ha_peer_info", "Info metrics regarding cluster HA peers", []string{"vdom", "hostname", "serial", "priority", "vcluster_id", "primary"}, nil, ) diff --git a/pkg/probe/system_ha_peer_test.go b/pkg/probe/system_ha_peer_test.go index cf7f2b0c..eb9a2181 100644 --- a/pkg/probe/system_ha_peer_test.go +++ b/pkg/probe/system_ha_peer_test.go @@ -21,10 +21,10 @@ func TestHAPeer(t *testing.T) { } em := ` - # HELP fortigate_ha_member_info Info metrics regarding cluster HA peers - # TYPE fortigate_ha_member_info gauge - fortigate_ha_member_info{hostname="member-name-1",primary="Unsupported",priority="200",serial="FGT61E4QXXXXXXXX1",vcluster_id="0",vdom="root"} 1 - fortigate_ha_member_info{hostname="member-name-2",primary="Unsupported",priority="100",serial="FGT61E4QXXXXXXXX2",vcluster_id="0",vdom="root"} 1 + # HELP fortigate_ha_peer_info Info metrics regarding cluster HA peers + # TYPE fortigate_ha_peer_info gauge + fortigate_ha_peer_info{hostname="member-name-1",primary="Unsupported",priority="200",serial="FGT61E4QXXXXXXXX1",vcluster_id="0",vdom="root"} 1 + fortigate_ha_peer_info{hostname="member-name-2",primary="Unsupported",priority="100",serial="FGT61E4QXXXXXXXX2",vcluster_id="0",vdom="root"} 1 ` if err := testutil.GatherAndCompare(r, strings.NewReader(em)); err != nil { @@ -45,10 +45,10 @@ func TestHAPeer74(t *testing.T) { } em := ` - # HELP fortigate_ha_member_info Info metrics regarding cluster HA peers - # TYPE fortigate_ha_member_info gauge - fortigate_ha_member_info{hostname="member-name-1",primary="true",priority="200",serial="FGT61E4QXXXXXXXX1",vcluster_id="0",vdom="root"} 1 - fortigate_ha_member_info{hostname="member-name-2",primary="false",priority="100",serial="FGT61E4QXXXXXXXX2",vcluster_id="0",vdom="root"} 1 + # HELP fortigate_ha_peer_info Info metrics regarding cluster HA peers + # TYPE fortigate_ha_peer_info gauge + fortigate_ha_peer_info{hostname="member-name-1",primary="true",priority="200",serial="FGT61E4QXXXXXXXX1",vcluster_id="0",vdom="root"} 1 + fortigate_ha_peer_info{hostname="member-name-2",primary="false",priority="100",serial="FGT61E4QXXXXXXXX2",vcluster_id="0",vdom="root"} 1 ` if err := testutil.GatherAndCompare(r, strings.NewReader(em)); err != nil {