diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 6a671b28..0efea0ca --- a/README.md +++ b/README.md @@ -183,6 +183,7 @@ To improve security, limit permissions to required ones only (least privilege pr |System/Central-management/Status | sysgrp.cfg |api/v2/monitor/system/central-management/status| |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/Interface/Transceivers| *any* |api/v2/monitor/system/interface/transceivers | |System/LinkMonitor | sysgrp.cfg |api/v2/monitor/system/link-monitor | diff --git a/metrics.md b/metrics.md index 018ea954..4bf334c8 100644 --- a/metrics.md +++ b/metrics.md @@ -37,6 +37,9 @@ Global: * `fortigate_system_performance_status_mem_used_bytes` * _System/HAChecksums_ * `fortigate_ha_member_has_role` + * _System/HAPeer_ + * `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/probe.go b/pkg/probe/probe.go index 24513f6e..ab681026 100644 --- a/pkg/probe/probe.go +++ b/pkg/probe/probe.go @@ -148,6 +148,7 @@ func (p *Collector) Probe(ctx context.Context, target map[string]string, hc *htt {"System/Central-Management/Status", probeSystemCentralManagementStatus}, {"System/Fortimanager/Status", probeSystemFortimanagerStatus}, {"System/HAStatistics", probeSystemHAStatistics}, + {"System/Ha-peer", probeSystemHaPeer}, {"System/Interface", probeSystemInterface}, {"System/Interface/Transceivers", probeSystemInterfaceTransceivers}, {"System/LinkMonitor", probeSystemLinkMonitor}, diff --git a/pkg/probe/system_ha_peer.go b/pkg/probe/system_ha_peer.go new file mode 100644 index 00000000..588bccdd --- /dev/null +++ b/pkg/probe/system_ha_peer.go @@ -0,0 +1,84 @@ +// 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 +// +// 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/client_golang/prometheus" + + "github.com/prometheus-community/fortigate_exporter/pkg/http" +) + +func probeSystemHaPeer(c http.FortiHTTP, meta *TargetMetadata) ([]prometheus.Metric, bool) { + 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{"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"` + 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(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)) + } 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 + } + } + 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..34769876 --- /dev/null +++ b/pkg/probe/system_ha_peer_test.go @@ -0,0 +1,77 @@ +// 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 +// +// 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_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 { + 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_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_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 + fortigate_ha_peer_primary{hostname="member-name-2",vcluster="0"} 0 + ` + + if err := testutil.GatherAndCompare(r, strings.NewReader(em)); err != nil { + t.Fatalf("metric compare: err %v", err) + } +} diff --git a/pkg/probe/testdata/system-ha-peer.jsonnet b/pkg/probe/testdata/system-ha-peer.jsonnet new file mode 100644 index 00000000..5d081a07 --- /dev/null +++ b/pkg/probe/testdata/system-ha-peer.jsonnet @@ -0,0 +1,28 @@ +# 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", + "master": true + } + ], + "vdom":"root", + "path":"system", + "name":"ha-peer", + "action":"", + "status":"success", + "serial":"FGT61E4QXXXXXXXX1", + "version":"v7.4.0", + "build":700 +} \ No newline at end of file