Skip to content

Commit e897bc8

Browse files
authored
Feature/system ntp status (#335)
* NTP probe added --------- Signed-off-by: Örnfeldt Philip (66140321) <[email protected]>
1 parent 31d00d9 commit e897bc8

File tree

5 files changed

+344
-0
lines changed

5 files changed

+344
-0
lines changed

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,14 @@ Global:
5353
* `fortigate_current_sessions`
5454
* _System/HAChecksums_
5555
* `fortigate_ha_member_has_role`
56+
* _System/Ntp/Status_
57+
* `fortigate_system_ntp_delay_seconds`
58+
* `fortigate_system_ntp_dispersion_seconds`
59+
* `fortigate_system_ntp_dispersion_peer_seconds`
60+
* `fortigate_system_ntp_expires_seconds`
61+
* `fortigate_system_ntp_offset_seconds`
62+
* `fortigate_system_ntp_reftime_seconds`
63+
* `fortigate_system_ntp_stratum`
5664
* _License/Status_
5765
* `fortigate_license_vdom_usage`
5866
* `fortigate_license_vdom_max`
@@ -418,6 +426,7 @@ To improve security, limit permissions to required ones only (least privilege pr
418426
|System/HAStatistics | sysgrp.cfg |api/v2/monitor/system/ha-statistics<br>api/v2/cmdb/system/ha |
419427
|System/Interface | netgrp.cfg |api/v2/monitor/system/interface/select |
420428
|System/LinkMonitor | sysgrp.cfg |api/v2/monitor/system/link-monitor |
429+
|System/Ntp/Status | netgrp.cfg |api/v2/monitor/system/ntp/status |
421430
|System/Resource/Usage | sysgrp.cfg |api/v2/monitor/system/resource/usage |
422431
|System/SensorInfo | sysgrp.cfg |api/v2/monitor/system/sensor-info |
423432
|System/Status | *any* |api/v2/monitor/system/status |

pkg/probe/probe.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ func (p *ProbeCollector) Probe(ctx context.Context, target map[string]string, hc
145145
{"System/HAStatistics", probeSystemHAStatistics},
146146
{"System/Interface", probeSystemInterface},
147147
{"System/LinkMonitor", probeSystemLinkMonitor},
148+
{"System/Ntp/Status", probeSystemNtpStatus},
148149
{"System/Resource/Usage", probeSystemResourceUsage},
149150
{"System/SDNConnector", probeSystemSDNConnector},
150151
{"System/SensorInfo", probeSystemSensorInfo},

pkg/probe/system_ntp_status.go

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// Copyright 2025 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-community/fortigate_exporter/pkg/http"
21+
"github.com/prometheus/client_golang/prometheus"
22+
)
23+
24+
func probeSystemNtpStatus(c http.FortiHTTP, meta *TargetMetadata) ([]prometheus.Metric, bool) {
25+
var (
26+
ntpExpires = prometheus.NewDesc(
27+
"fortigate_system_ntp_expires_seconds",
28+
"NTP expire time, in seconds",
29+
[]string{"ip", "server", "reachable", "selected", "version", "vdom"}, nil,
30+
)
31+
ntpStratum = prometheus.NewDesc(
32+
"fortigate_system_ntp_stratum",
33+
"NTP stratum value",
34+
[]string{"ip", "server", "reachable", "selected", "version", "vdom"}, nil,
35+
)
36+
ntpRefTime = prometheus.NewDesc(
37+
"fortigate_system_ntp_reftime_seconds",
38+
"NTP reftime in epoch seconds",
39+
[]string{"ip", "server", "reachable", "selected", "version", "vdom"}, nil,
40+
)
41+
ntpOffset = prometheus.NewDesc(
42+
"fortigate_system_ntp_offset_seconds",
43+
"NTP combined offset, in seconds",
44+
[]string{"ip", "server", "reachable", "selected", "version", "vdom"}, nil,
45+
)
46+
ntpDelay = prometheus.NewDesc(
47+
"fortigate_system_ntp_delay_seconds",
48+
"NTP round trip delay, in seconds",
49+
[]string{"ip", "server", "reachable", "selected", "version", "vdom"}, nil,
50+
)
51+
ntpDispersion = prometheus.NewDesc(
52+
"fortigate_system_ntp_dispersion_seconds",
53+
"NTP dispersion to primary clock, in seconds",
54+
[]string{"ip", "server", "reachable", "selected", "version", "vdom"}, nil,
55+
)
56+
ntpPeerDispersion = prometheus.NewDesc(
57+
"fortigate_system_ntp_dispersion_peer_seconds",
58+
"NTP peer dispersion, in seconds",
59+
[]string{"ip", "server", "reachable", "selected", "version", "vdom"}, nil,
60+
)
61+
)
62+
63+
type SystemNtpStatus struct {
64+
Ip string `json:"ip"`
65+
Server string `json:"server"`
66+
Reachable bool `json:"reachable"`
67+
Expires int `json:"expires"`
68+
Selected bool `json:"selected"`
69+
Version int `json:"version"`
70+
Stratum int `json:"stratum"`
71+
Reftime int `json:"reftime"`
72+
Offset float64 `json:"offset"`
73+
Delay float64 `json:"delay"`
74+
Dispersion float64 `json:"dispersion"`
75+
PeerDispersion int `json:"peer_dispersion"`
76+
}
77+
78+
type SystemNtpStatusResult struct {
79+
Results []SystemNtpStatus `json:"results"`
80+
VDOM string `json:"vdom"`
81+
}
82+
83+
var result []SystemNtpStatusResult
84+
if err := c.Get("api/v2/monitor/system/ntp/status","vdom=*",&result); err != nil {
85+
log.Printf("Error: %v", err)
86+
return nil, false
87+
}
88+
89+
m := []prometheus.Metric{}
90+
if meta.VersionMajor >=7 && meta.VersionMinor >=4 {
91+
for _, res := range result {
92+
for _, r := range res.Results {
93+
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))
94+
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))
95+
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))
96+
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))
97+
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))
98+
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))
99+
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))
100+
}
101+
}
102+
} else {
103+
log.Printf("Not implemented in versions under 7.4")
104+
}
105+
return m, true
106+
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// Copyright 2025 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 TestSystemNtpStatus_7_4_0(t *testing.T) {
25+
c := newFakeClient()
26+
c.prepare("api/v2/monitor/system/ntp/status", "testdata/system-ntp-status.jsonnet")
27+
meta := &TargetMetadata{
28+
VersionMajor: 7,
29+
VersionMinor: 4,
30+
}
31+
r := prometheus.NewPedanticRegistry()
32+
if !testProbeWithMetadata(probeSystemNtpStatus, c, meta, r) {
33+
t.Errorf("probeSystemNtpStatus() returned non-success")
34+
}
35+
36+
em := `# HELP fortigate_system_ntp_delay_seconds NTP round trip delay, in seconds
37+
# TYPE fortigate_system_ntp_delay_seconds gauge
38+
fortigate_system_ntp_delay_seconds{ip="127.0.0.1",reachable="true",selected="true",server="HA-TEST",vdom="google",version="1035"} 0.324
39+
fortigate_system_ntp_delay_seconds{ip="127.0.0.1",reachable="true",selected="true",server="HA-TEST",vdom="vdomtest",version="1035"} 0.324
40+
fortigate_system_ntp_delay_seconds{ip="127.0.0.2",reachable="false",selected="false",server="HA-CAP",vdom="google",version="1035"} 0.324
41+
fortigate_system_ntp_delay_seconds{ip="127.0.0.2",reachable="false",selected="false",server="HA-CAP",vdom="vdomtest",version="1035"} 0.324
42+
fortigate_system_ntp_delay_seconds{ip="127.0.0.3",reachable="true",selected="true",server="HA-CODE",vdom="google",version="1035"} 0.324
43+
fortigate_system_ntp_delay_seconds{ip="127.0.0.3",reachable="true",selected="true",server="HA-CODE",vdom="vdomtest",version="1035"} 0.324
44+
# HELP fortigate_system_ntp_dispersion_seconds NTP dispersion to primary clock, in seconds
45+
# TYPE fortigate_system_ntp_dispersion_seconds gauge
46+
fortigate_system_ntp_dispersion_seconds{ip="127.0.0.1",reachable="true",selected="true",server="HA-TEST",vdom="google",version="1035"} 0.342
47+
fortigate_system_ntp_dispersion_seconds{ip="127.0.0.1",reachable="true",selected="true",server="HA-TEST",vdom="vdomtest",version="1035"} 0.342
48+
fortigate_system_ntp_dispersion_seconds{ip="127.0.0.2",reachable="false",selected="false",server="HA-CAP",vdom="google",version="1035"} 0.342
49+
fortigate_system_ntp_dispersion_seconds{ip="127.0.0.2",reachable="false",selected="false",server="HA-CAP",vdom="vdomtest",version="1035"} 0.342
50+
fortigate_system_ntp_dispersion_seconds{ip="127.0.0.3",reachable="true",selected="true",server="HA-CODE",vdom="google",version="1035"} 0.342
51+
fortigate_system_ntp_dispersion_seconds{ip="127.0.0.3",reachable="true",selected="true",server="HA-CODE",vdom="vdomtest",version="1035"} 0.342
52+
# HELP fortigate_system_ntp_dispersion_peer_seconds NTP peer dispersion, in seconds
53+
# TYPE fortigate_system_ntp_dispersion_peer_seconds gauge
54+
fortigate_system_ntp_dispersion_peer_seconds{ip="127.0.0.1",reachable="true",selected="true",server="HA-TEST",vdom="google",version="1035"} 0.123
55+
fortigate_system_ntp_dispersion_peer_seconds{ip="127.0.0.1",reachable="true",selected="true",server="HA-TEST",vdom="vdomtest",version="1035"} 0.123
56+
fortigate_system_ntp_dispersion_peer_seconds{ip="127.0.0.2",reachable="false",selected="false",server="HA-CAP",vdom="google",version="1035"} 0.123
57+
fortigate_system_ntp_dispersion_peer_seconds{ip="127.0.0.2",reachable="false",selected="false",server="HA-CAP",vdom="vdomtest",version="1035"} 0.123
58+
fortigate_system_ntp_dispersion_peer_seconds{ip="127.0.0.3",reachable="true",selected="true",server="HA-CODE",vdom="google",version="1035"} 0.123
59+
fortigate_system_ntp_dispersion_peer_seconds{ip="127.0.0.3",reachable="true",selected="true",server="HA-CODE",vdom="vdomtest",version="1035"} 0.123
60+
# HELP fortigate_system_ntp_expires_seconds NTP expire time, in seconds
61+
# TYPE fortigate_system_ntp_expires_seconds gauge
62+
fortigate_system_ntp_expires_seconds{ip="127.0.0.1",reachable="true",selected="true",server="HA-TEST",vdom="google",version="1035"} 145438
63+
fortigate_system_ntp_expires_seconds{ip="127.0.0.1",reachable="true",selected="true",server="HA-TEST",vdom="vdomtest",version="1035"} 145438
64+
fortigate_system_ntp_expires_seconds{ip="127.0.0.2",reachable="false",selected="false",server="HA-CAP",vdom="google",version="1035"} 124438
65+
fortigate_system_ntp_expires_seconds{ip="127.0.0.2",reachable="false",selected="false",server="HA-CAP",vdom="vdomtest",version="1035"} 124438
66+
fortigate_system_ntp_expires_seconds{ip="127.0.0.3",reachable="true",selected="true",server="HA-CODE",vdom="google",version="1035"} 245438
67+
fortigate_system_ntp_expires_seconds{ip="127.0.0.3",reachable="true",selected="true",server="HA-CODE",vdom="vdomtest",version="1035"} 245438
68+
# HELP fortigate_system_ntp_offset_seconds NTP combined offset, in seconds
69+
# TYPE fortigate_system_ntp_offset_seconds gauge
70+
fortigate_system_ntp_offset_seconds{ip="127.0.0.1",reachable="true",selected="true",server="HA-TEST",vdom="google",version="1035"} 5.482
71+
fortigate_system_ntp_offset_seconds{ip="127.0.0.1",reachable="true",selected="true",server="HA-TEST",vdom="vdomtest",version="1035"} 5.482
72+
fortigate_system_ntp_offset_seconds{ip="127.0.0.2",reachable="false",selected="false",server="HA-CAP",vdom="google",version="1035"} 5.482
73+
fortigate_system_ntp_offset_seconds{ip="127.0.0.2",reachable="false",selected="false",server="HA-CAP",vdom="vdomtest",version="1035"} 5.482
74+
fortigate_system_ntp_offset_seconds{ip="127.0.0.3",reachable="true",selected="true",server="HA-CODE",vdom="google",version="1035"} 5.482
75+
fortigate_system_ntp_offset_seconds{ip="127.0.0.3",reachable="true",selected="true",server="HA-CODE",vdom="vdomtest",version="1035"} 5.482
76+
# HELP fortigate_system_ntp_reftime_seconds NTP reftime in epoch seconds
77+
# TYPE fortigate_system_ntp_reftime_seconds counter
78+
fortigate_system_ntp_reftime_seconds{ip="127.0.0.1",reachable="true",selected="true",server="HA-TEST",vdom="google",version="1035"} 85742
79+
fortigate_system_ntp_reftime_seconds{ip="127.0.0.1",reachable="true",selected="true",server="HA-TEST",vdom="vdomtest",version="1035"} 85742
80+
fortigate_system_ntp_reftime_seconds{ip="127.0.0.2",reachable="false",selected="false",server="HA-CAP",vdom="google",version="1035"} 85742
81+
fortigate_system_ntp_reftime_seconds{ip="127.0.0.2",reachable="false",selected="false",server="HA-CAP",vdom="vdomtest",version="1035"} 85742
82+
fortigate_system_ntp_reftime_seconds{ip="127.0.0.3",reachable="true",selected="true",server="HA-CODE",vdom="google",version="1035"} 85742
83+
fortigate_system_ntp_reftime_seconds{ip="127.0.0.3",reachable="true",selected="true",server="HA-CODE",vdom="vdomtest",version="1035"} 85742
84+
# HELP fortigate_system_ntp_stratum NTP stratum value
85+
# TYPE fortigate_system_ntp_stratum gauge
86+
fortigate_system_ntp_stratum{ip="127.0.0.1",reachable="true",selected="true",server="HA-TEST",vdom="google",version="1035"} 3
87+
fortigate_system_ntp_stratum{ip="127.0.0.1",reachable="true",selected="true",server="HA-TEST",vdom="vdomtest",version="1035"} 3
88+
fortigate_system_ntp_stratum{ip="127.0.0.2",reachable="false",selected="false",server="HA-CAP",vdom="google",version="1035"} 3
89+
fortigate_system_ntp_stratum{ip="127.0.0.2",reachable="false",selected="false",server="HA-CAP",vdom="vdomtest",version="1035"} 3
90+
fortigate_system_ntp_stratum{ip="127.0.0.3",reachable="true",selected="true",server="HA-CODE",vdom="google",version="1035"} 3
91+
fortigate_system_ntp_stratum{ip="127.0.0.3",reachable="true",selected="true",server="HA-CODE",vdom="vdomtest",version="1035"} 3
92+
`
93+
94+
if err := testutil.CollectAndCompare(r, strings.NewReader(em)); err != nil {
95+
t.Fatalf("metric compare: err %v", err)
96+
}
97+
}
98+
99+
func TestSystemNtpStatus(t *testing.T) {
100+
c := newFakeClient()
101+
c.prepare("api/v2/monitor/system/ntp/status", "testdata/system-ntp-status.jsonnet")
102+
meta := &TargetMetadata{
103+
VersionMajor: 7,
104+
VersionMinor: 2,
105+
}
106+
r := prometheus.NewPedanticRegistry()
107+
if !testProbeWithMetadata(probeSystemNtpStatus, c, meta, r) {
108+
t.Errorf("probeSystemNtpStatus() returned non-success")
109+
}
110+
111+
em := ``
112+
113+
if err := testutil.CollectAndCompare(r, strings.NewReader(em)); err != nil {
114+
t.Fatalf("metric compare: err %v", err)
115+
}
116+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
[
2+
{
3+
"http_method":"GET",
4+
"results":[
5+
{
6+
"ip": "127.0.0.1",
7+
"server": "HA-TEST",
8+
"reachable": true,
9+
"expires": 145438,
10+
"selected": false,
11+
"version": 1035,
12+
"stratum": 3,
13+
"reftime": 85742,
14+
"offset": 5482,
15+
"delay": 324,
16+
"dispersion": 342,
17+
"peer_dispersion": 123
18+
},
19+
{
20+
"ip": "127.0.0.2",
21+
"server": "HA-CAP",
22+
"reachable": false,
23+
"expires": 124438,
24+
"selected": true,
25+
"version": 1035,
26+
"stratum": 3,
27+
"reftime": 85742,
28+
"offset": 5482,
29+
"delay": 324,
30+
"dispersion": 342,
31+
"peer_dispersion": 123
32+
},
33+
{
34+
"ip": "127.0.0.3",
35+
"server": "HA-CODE",
36+
"reachable": true,
37+
"expires": 245438,
38+
"selected": true,
39+
"version": 1035,
40+
"stratum": 3,
41+
"reftime": 85742,
42+
"offset": 5482,
43+
"delay": 324,
44+
"dispersion": 342,
45+
"peer_dispersion": 123
46+
}
47+
],
48+
"vdom":"google",
49+
"path":"system",
50+
"name":"sdn-connector",
51+
"action":"status",
52+
"status":"success",
53+
"serial":"FGABCDEF12345678",
54+
"version":"v7.0.9",
55+
"build":444
56+
},
57+
{
58+
"http_method":"GET",
59+
"results":[
60+
{
61+
"ip": "127.0.0.1",
62+
"server": "HA-TEST",
63+
"reachable": true,
64+
"expires": 145438,
65+
"selected": false,
66+
"version": 1035,
67+
"stratum": 3,
68+
"reftime": 85742,
69+
"offset": 5482,
70+
"delay": 324,
71+
"dispersion": 342,
72+
"peer_dispersion": 123
73+
},
74+
{
75+
"ip": "127.0.0.2",
76+
"server": "HA-CAP",
77+
"reachable": false,
78+
"expires": 124438,
79+
"selected": true,
80+
"version": 1035,
81+
"stratum": 3,
82+
"reftime": 85742,
83+
"offset": 5482,
84+
"delay": 324,
85+
"dispersion": 342,
86+
"peer_dispersion": 123
87+
},
88+
{
89+
"ip": "127.0.0.3",
90+
"server": "HA-CODE",
91+
"reachable": true,
92+
"expires": 245438,
93+
"selected": true,
94+
"version": 1035,
95+
"stratum": 3,
96+
"reftime": 85742,
97+
"offset": 5482,
98+
"delay": 324,
99+
"dispersion": 342,
100+
"peer_dispersion": 123
101+
}
102+
],
103+
"vdom":"vdomtest",
104+
"path":"system",
105+
"name":"sdn-connector",
106+
"action":"status",
107+
"status":"success",
108+
"serial":"FGABCDEF12345678",
109+
"version":"v7.0.9",
110+
"build":444
111+
}
112+
]

0 commit comments

Comments
 (0)