Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ Global:
* `fortigate_current_sessions`
* _System/HAChecksums_
* `fortigate_ha_member_has_role`
* _System/Ntp/Status_
* `fortigate_system_ntp_delay_seconds`
* `fortigate_system_ntp_dispersion_seconds`
* `fortigate_system_ntp_dispersion_peer_seconds`
* `fortigate_system_ntp_expires_seconds`
* `fortigate_system_ntp_offset_seconds`
* `fortigate_system_ntp_reftime_seconds`
* `fortigate_system_ntp_stratum`
* _License/Status_
* `fortigate_license_vdom_usage`
* `fortigate_license_vdom_max`
Expand Down Expand Up @@ -416,6 +424,7 @@ To improve security, limit permissions to required ones only (least privilege pr
|System/HAStatistics | sysgrp.cfg |api/v2/monitor/system/ha-statistics<br>api/v2/cmdb/system/ha |
|System/Interface | netgrp.cfg |api/v2/monitor/system/interface/select |
|System/LinkMonitor | sysgrp.cfg |api/v2/monitor/system/link-monitor |
|System/Ntp/Status | netgrp.cfg |api/v2/monitor/system/ntp/status |
|System/Resource/Usage | sysgrp.cfg |api/v2/monitor/system/resource/usage |
|System/SensorInfo | sysgrp.cfg |api/v2/monitor/system/sensor-info |
|System/Status | *any* |api/v2/monitor/system/status |
Expand Down
1 change: 1 addition & 0 deletions pkg/probe/probe.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ func (p *ProbeCollector) Probe(ctx context.Context, target map[string]string, hc
{"System/HAStatistics", probeSystemHAStatistics},
{"System/Interface", probeSystemInterface},
{"System/LinkMonitor", probeSystemLinkMonitor},
{"System/Ntp/Status", probeSystemNtpStatus},
{"System/Resource/Usage", probeSystemResourceUsage},
{"System/SDNConnector", probeSystemSDNConnector},
{"System/SensorInfo", probeSystemSensorInfo},
Expand Down
106 changes: 106 additions & 0 deletions pkg/probe/system_ntp_status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// 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 probeSystemNtpStatus(c http.FortiHTTP, meta *TargetMetadata) ([]prometheus.Metric, bool) {
var (
ntpExpires = prometheus.NewDesc(
"fortigate_system_ntp_expires_seconds",
"NTP expire time, in seconds",
[]string{"ip", "server", "reachable", "selected", "version", "vdom"}, nil,
)
ntpStratum = prometheus.NewDesc(
"fortigate_system_ntp_stratum",
"NTP stratum value",
[]string{"ip", "server", "reachable", "selected", "version", "vdom"}, nil,
)
ntpRefTime = prometheus.NewDesc(
"fortigate_system_ntp_reftime_seconds",
"NTP reftime in epoch seconds",
[]string{"ip", "server", "reachable", "selected", "version", "vdom"}, nil,
)
ntpOffset = prometheus.NewDesc(
"fortigate_system_ntp_offset_seconds",
"NTP combined offset, in seconds",
[]string{"ip", "server", "reachable", "selected", "version", "vdom"}, nil,
)
ntpDelay = prometheus.NewDesc(
"fortigate_system_ntp_delay_seconds",
"NTP round trip delay, in seconds",
[]string{"ip", "server", "reachable", "selected", "version", "vdom"}, nil,
)
ntpDispersion = prometheus.NewDesc(
"fortigate_system_ntp_dispersion_seconds",
"NTP dispersion to primary clock, in seconds",
[]string{"ip", "server", "reachable", "selected", "version", "vdom"}, nil,
)
ntpPeerDispersion = prometheus.NewDesc(
"fortigate_system_ntp_dispersion_peer_seconds",
"NTP peer dispersion, in seconds",
[]string{"ip", "server", "reachable", "selected", "version", "vdom"}, nil,
)
)

type SystemNtpStatus struct {
Ip string `json:"ip"`
Server string `json:"server"`
Reachable bool `json:"reachable"`
Expires int `json:"expires"`
Selected bool `json:"selected"`
Version int `json:"version"`
Stratum int `json:"stratum"`
Reftime int `json:"reftime"`
Offset float64 `json:"offset"`
Delay float64 `json:"delay"`
Dispersion float64 `json:"dispersion"`
PeerDispersion int `json:"peer_dispersion"`
}

type SystemNtpStatusResult struct {
Results []SystemNtpStatus `json:"results"`
VDOM string `json:"vdom"`
}

var result []SystemNtpStatusResult
if err := c.Get("api/v2/monitor/system/ntp/status","vdom=*",&result); err != nil {
log.Printf("Error: %v", err)
return nil, false
}

m := []prometheus.Metric{}
if meta.VersionMajor >=7 && meta.VersionMinor >=4 {
for _, res := range result {
for _, r := range res.Results {
m = append(m, prometheus.MustNewConstMetric(ntpExpires, prometheus.GaugeValue, float64(r.Expires), r.Ip, r.Server, strconv.FormatBool(r.Reachable), strconv.FormatBool(r.Reachable), strconv.Itoa(r.Version), res.VDOM))
m = append(m, prometheus.MustNewConstMetric(ntpStratum, prometheus.GaugeValue, float64(r.Stratum), r.Ip, r.Server, strconv.FormatBool(r.Reachable), strconv.FormatBool(r.Reachable), strconv.Itoa(r.Version), res.VDOM))
m = append(m, prometheus.MustNewConstMetric(ntpRefTime, prometheus.CounterValue, float64(r.Reftime), r.Ip, r.Server, strconv.FormatBool(r.Reachable), strconv.FormatBool(r.Reachable), strconv.Itoa(r.Version), res.VDOM))
m = append(m, prometheus.MustNewConstMetric(ntpOffset, prometheus.GaugeValue, float64(r.Offset) * 0.001, r.Ip, r.Server, strconv.FormatBool(r.Reachable), strconv.FormatBool(r.Reachable), strconv.Itoa(r.Version), res.VDOM))
m = append(m, prometheus.MustNewConstMetric(ntpDelay, prometheus.GaugeValue, float64(r.Delay) * 0.001, r.Ip, r.Server, strconv.FormatBool(r.Reachable), strconv.FormatBool(r.Reachable), strconv.Itoa(r.Version), res.VDOM))
m = append(m, prometheus.MustNewConstMetric(ntpDispersion, prometheus.GaugeValue, float64(r.Dispersion) * 0.001, r.Ip, r.Server, strconv.FormatBool(r.Reachable), strconv.FormatBool(r.Reachable), strconv.Itoa(r.Version), res.VDOM))
m = append(m, prometheus.MustNewConstMetric(ntpPeerDispersion, prometheus.GaugeValue, float64(r.PeerDispersion) * 0.001, r.Ip, r.Server, strconv.FormatBool(r.Reachable), strconv.FormatBool(r.Reachable), strconv.Itoa(r.Version), res.VDOM))
}
}
} else {
log.Printf("Not implemented in versions under 7.4")
}
return m, true
}
116 changes: 116 additions & 0 deletions pkg/probe/system_ntp_status_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// 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 TestSystemNtpStatus_7_4_0(t *testing.T) {
c := newFakeClient()
c.prepare("api/v2/monitor/system/ntp/status", "testdata/system-ntp-status.jsonnet")
meta := &TargetMetadata{
VersionMajor: 7,
VersionMinor: 4,
}
r := prometheus.NewPedanticRegistry()
if !testProbeWithMetadata(probeSystemNtpStatus, c, meta, r) {
t.Errorf("probeSystemNtpStatus() returned non-success")
}

em := `# HELP fortigate_system_ntp_delay_seconds NTP round trip delay, in seconds
# TYPE fortigate_system_ntp_delay_seconds gauge
fortigate_system_ntp_delay_seconds{ip="127.0.0.1",reachable="true",selected="true",server="HA-TEST",vdom="google",version="1035"} 0.324
fortigate_system_ntp_delay_seconds{ip="127.0.0.1",reachable="true",selected="true",server="HA-TEST",vdom="vdomtest",version="1035"} 0.324
fortigate_system_ntp_delay_seconds{ip="127.0.0.2",reachable="false",selected="false",server="HA-CAP",vdom="google",version="1035"} 0.324
fortigate_system_ntp_delay_seconds{ip="127.0.0.2",reachable="false",selected="false",server="HA-CAP",vdom="vdomtest",version="1035"} 0.324
fortigate_system_ntp_delay_seconds{ip="127.0.0.3",reachable="true",selected="true",server="HA-CODE",vdom="google",version="1035"} 0.324
fortigate_system_ntp_delay_seconds{ip="127.0.0.3",reachable="true",selected="true",server="HA-CODE",vdom="vdomtest",version="1035"} 0.324
# HELP fortigate_system_ntp_dispersion_seconds NTP dispersion to primary clock, in seconds
# TYPE fortigate_system_ntp_dispersion_seconds gauge
fortigate_system_ntp_dispersion_seconds{ip="127.0.0.1",reachable="true",selected="true",server="HA-TEST",vdom="google",version="1035"} 0.342
fortigate_system_ntp_dispersion_seconds{ip="127.0.0.1",reachable="true",selected="true",server="HA-TEST",vdom="vdomtest",version="1035"} 0.342
fortigate_system_ntp_dispersion_seconds{ip="127.0.0.2",reachable="false",selected="false",server="HA-CAP",vdom="google",version="1035"} 0.342
fortigate_system_ntp_dispersion_seconds{ip="127.0.0.2",reachable="false",selected="false",server="HA-CAP",vdom="vdomtest",version="1035"} 0.342
fortigate_system_ntp_dispersion_seconds{ip="127.0.0.3",reachable="true",selected="true",server="HA-CODE",vdom="google",version="1035"} 0.342
fortigate_system_ntp_dispersion_seconds{ip="127.0.0.3",reachable="true",selected="true",server="HA-CODE",vdom="vdomtest",version="1035"} 0.342
# HELP fortigate_system_ntp_dispersion_peer_seconds NTP peer dispersion, in seconds
# TYPE fortigate_system_ntp_dispersion_peer_seconds gauge
fortigate_system_ntp_dispersion_peer_seconds{ip="127.0.0.1",reachable="true",selected="true",server="HA-TEST",vdom="google",version="1035"} 0.123
fortigate_system_ntp_dispersion_peer_seconds{ip="127.0.0.1",reachable="true",selected="true",server="HA-TEST",vdom="vdomtest",version="1035"} 0.123
fortigate_system_ntp_dispersion_peer_seconds{ip="127.0.0.2",reachable="false",selected="false",server="HA-CAP",vdom="google",version="1035"} 0.123
fortigate_system_ntp_dispersion_peer_seconds{ip="127.0.0.2",reachable="false",selected="false",server="HA-CAP",vdom="vdomtest",version="1035"} 0.123
fortigate_system_ntp_dispersion_peer_seconds{ip="127.0.0.3",reachable="true",selected="true",server="HA-CODE",vdom="google",version="1035"} 0.123
fortigate_system_ntp_dispersion_peer_seconds{ip="127.0.0.3",reachable="true",selected="true",server="HA-CODE",vdom="vdomtest",version="1035"} 0.123
# HELP fortigate_system_ntp_expires_seconds NTP expire time, in seconds
# TYPE fortigate_system_ntp_expires_seconds gauge
fortigate_system_ntp_expires_seconds{ip="127.0.0.1",reachable="true",selected="true",server="HA-TEST",vdom="google",version="1035"} 145438
fortigate_system_ntp_expires_seconds{ip="127.0.0.1",reachable="true",selected="true",server="HA-TEST",vdom="vdomtest",version="1035"} 145438
fortigate_system_ntp_expires_seconds{ip="127.0.0.2",reachable="false",selected="false",server="HA-CAP",vdom="google",version="1035"} 124438
fortigate_system_ntp_expires_seconds{ip="127.0.0.2",reachable="false",selected="false",server="HA-CAP",vdom="vdomtest",version="1035"} 124438
fortigate_system_ntp_expires_seconds{ip="127.0.0.3",reachable="true",selected="true",server="HA-CODE",vdom="google",version="1035"} 245438
fortigate_system_ntp_expires_seconds{ip="127.0.0.3",reachable="true",selected="true",server="HA-CODE",vdom="vdomtest",version="1035"} 245438
# HELP fortigate_system_ntp_offset_seconds NTP combined offset, in seconds
# TYPE fortigate_system_ntp_offset_seconds gauge
fortigate_system_ntp_offset_seconds{ip="127.0.0.1",reachable="true",selected="true",server="HA-TEST",vdom="google",version="1035"} 5.482
fortigate_system_ntp_offset_seconds{ip="127.0.0.1",reachable="true",selected="true",server="HA-TEST",vdom="vdomtest",version="1035"} 5.482
fortigate_system_ntp_offset_seconds{ip="127.0.0.2",reachable="false",selected="false",server="HA-CAP",vdom="google",version="1035"} 5.482
fortigate_system_ntp_offset_seconds{ip="127.0.0.2",reachable="false",selected="false",server="HA-CAP",vdom="vdomtest",version="1035"} 5.482
fortigate_system_ntp_offset_seconds{ip="127.0.0.3",reachable="true",selected="true",server="HA-CODE",vdom="google",version="1035"} 5.482
fortigate_system_ntp_offset_seconds{ip="127.0.0.3",reachable="true",selected="true",server="HA-CODE",vdom="vdomtest",version="1035"} 5.482
# HELP fortigate_system_ntp_reftime_seconds NTP reftime in epoch seconds
# TYPE fortigate_system_ntp_reftime_seconds counter
fortigate_system_ntp_reftime_seconds{ip="127.0.0.1",reachable="true",selected="true",server="HA-TEST",vdom="google",version="1035"} 85742
fortigate_system_ntp_reftime_seconds{ip="127.0.0.1",reachable="true",selected="true",server="HA-TEST",vdom="vdomtest",version="1035"} 85742
fortigate_system_ntp_reftime_seconds{ip="127.0.0.2",reachable="false",selected="false",server="HA-CAP",vdom="google",version="1035"} 85742
fortigate_system_ntp_reftime_seconds{ip="127.0.0.2",reachable="false",selected="false",server="HA-CAP",vdom="vdomtest",version="1035"} 85742
fortigate_system_ntp_reftime_seconds{ip="127.0.0.3",reachable="true",selected="true",server="HA-CODE",vdom="google",version="1035"} 85742
fortigate_system_ntp_reftime_seconds{ip="127.0.0.3",reachable="true",selected="true",server="HA-CODE",vdom="vdomtest",version="1035"} 85742
# HELP fortigate_system_ntp_stratum NTP stratum value
# TYPE fortigate_system_ntp_stratum gauge
fortigate_system_ntp_stratum{ip="127.0.0.1",reachable="true",selected="true",server="HA-TEST",vdom="google",version="1035"} 3
fortigate_system_ntp_stratum{ip="127.0.0.1",reachable="true",selected="true",server="HA-TEST",vdom="vdomtest",version="1035"} 3
fortigate_system_ntp_stratum{ip="127.0.0.2",reachable="false",selected="false",server="HA-CAP",vdom="google",version="1035"} 3
fortigate_system_ntp_stratum{ip="127.0.0.2",reachable="false",selected="false",server="HA-CAP",vdom="vdomtest",version="1035"} 3
fortigate_system_ntp_stratum{ip="127.0.0.3",reachable="true",selected="true",server="HA-CODE",vdom="google",version="1035"} 3
fortigate_system_ntp_stratum{ip="127.0.0.3",reachable="true",selected="true",server="HA-CODE",vdom="vdomtest",version="1035"} 3
`

if err := testutil.CollectAndCompare(r, strings.NewReader(em)); err != nil {
t.Fatalf("metric compare: err %v", err)
}
}

func TestSystemNtpStatus(t *testing.T) {
c := newFakeClient()
c.prepare("api/v2/monitor/system/ntp/status", "testdata/system-ntp-status.jsonnet")
meta := &TargetMetadata{
VersionMajor: 7,
VersionMinor: 2,
}
r := prometheus.NewPedanticRegistry()
if !testProbeWithMetadata(probeSystemNtpStatus, c, meta, r) {
t.Errorf("probeSystemNtpStatus() returned non-success")
}

em := ``

if err := testutil.CollectAndCompare(r, strings.NewReader(em)); err != nil {
t.Fatalf("metric compare: err %v", err)
}
}
112 changes: 112 additions & 0 deletions pkg/probe/testdata/system-ntp-status.jsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
[
{
"http_method":"GET",
"results":[
{
"ip": "127.0.0.1",
"server": "HA-TEST",
"reachable": true,
"expires": 145438,
"selected": false,
"version": 1035,
"stratum": 3,
"reftime": 85742,
"offset": 5482,
"delay": 324,
"dispersion": 342,
"peer_dispersion": 123
},
{
"ip": "127.0.0.2",
"server": "HA-CAP",
"reachable": false,
"expires": 124438,
"selected": true,
"version": 1035,
"stratum": 3,
"reftime": 85742,
"offset": 5482,
"delay": 324,
"dispersion": 342,
"peer_dispersion": 123
},
{
"ip": "127.0.0.3",
"server": "HA-CODE",
"reachable": true,
"expires": 245438,
"selected": true,
"version": 1035,
"stratum": 3,
"reftime": 85742,
"offset": 5482,
"delay": 324,
"dispersion": 342,
"peer_dispersion": 123
}
],
"vdom":"google",
"path":"system",
"name":"sdn-connector",
"action":"status",
"status":"success",
"serial":"FGABCDEF12345678",
"version":"v7.0.9",
"build":444
},
{
"http_method":"GET",
"results":[
{
"ip": "127.0.0.1",
"server": "HA-TEST",
"reachable": true,
"expires": 145438,
"selected": false,
"version": 1035,
"stratum": 3,
"reftime": 85742,
"offset": 5482,
"delay": 324,
"dispersion": 342,
"peer_dispersion": 123
},
{
"ip": "127.0.0.2",
"server": "HA-CAP",
"reachable": false,
"expires": 124438,
"selected": true,
"version": 1035,
"stratum": 3,
"reftime": 85742,
"offset": 5482,
"delay": 324,
"dispersion": 342,
"peer_dispersion": 123
},
{
"ip": "127.0.0.3",
"server": "HA-CODE",
"reachable": true,
"expires": 245438,
"selected": true,
"version": 1035,
"stratum": 3,
"reftime": 85742,
"offset": 5482,
"delay": 324,
"dispersion": 342,
"peer_dispersion": 123
}
],
"vdom":"vdomtest",
"path":"system",
"name":"sdn-connector",
"action":"status",
"status":"success",
"serial":"FGABCDEF12345678",
"version":"v7.0.9",
"build":444
}
]
Loading