diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 6a671b28..96a8ca2a --- a/README.md +++ b/README.md @@ -192,6 +192,9 @@ To improve security, limit permissions to required ones only (least privilege pr |System/Resource/Usage/VDOM | 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 | +|System/Sandbox/Connection | sysgrp.cfg |api/v2/monitor/system/sandbox/connection| +|System/Sandbox/Status | sysgrp.cfg |api/v2/monitor/system/sandbox/status| +|System/Sandbox/Stats | sysgrp.cfg |api/v2/monitor/system/sandbox/stats| |System/Time/Clock | sysgrp.cfg |api/v2/monitor/system/time | |System/System/VDOMResource | sysgrp.cfg |api/v2/monitor/system/vdom-resource | |User/Fsso | authgrp |api/v2/monitor/user/fsso | diff --git a/metrics.md b/metrics.md index 018ea954..41992632 100644 --- a/metrics.md +++ b/metrics.md @@ -51,6 +51,15 @@ Global: * _WebUI/State_ * `fortigate_last_reboot_seconds` * `fortigate_last_snapshot_seconds` + * _System/Sandbox_ + * `fortigate_sandbox_status_signature_count` + * `fortigate_sandbox_connection_status` + * `fortigate_sandbox_stats_clean_total` + * `fortigate_sandbox_stats_detected_total` + * `fortigate_sandbox_stats_risk_high_total` + * `fortigate_sandbox_stats_risk_medium_total` + * `fortigate_sandbox_stats_risk_low_total` + * `fortigate_sandbox_stats_submitted_total` Per-VDOM: diff --git a/pkg/probe/probe.go b/pkg/probe/probe.go index 24513f6e..e89fe763 100644 --- a/pkg/probe/probe.go +++ b/pkg/probe/probe.go @@ -160,6 +160,9 @@ func (p *Collector) Probe(ctx context.Context, target map[string]string, hc *htt {"System/Status", probeSystemStatus}, {"System/VDOMResource", probeSystemVdomResource}, {"System/HAChecksum", probeSystemHAChecksum}, + {"System/Sandbox/Connection", probeSystemSandboxConnection}, + {"System/Sandbox/Status", probeSystemSandboxStatus}, + {"System/Sandbox/Stats", probeSystemSandboxStats}, {"User/Fsso", probeUserFsso}, {"VPN/IPSec", probeVPNIPSec}, {"VPN/Ssl/Connections", probeVPNSsl}, diff --git a/pkg/probe/system_sandbox_connection.go b/pkg/probe/system_sandbox_connection.go new file mode 100644 index 00000000..bb5d6cae --- /dev/null +++ b/pkg/probe/system_sandbox_connection.go @@ -0,0 +1,73 @@ +// 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" + + "github.com/prometheus/client_golang/prometheus" + + "github.com/prometheus-community/fortigate_exporter/pkg/http" +) + +func probeSystemSandboxConnection(c http.FortiHTTP, _ *TargetMetadata) ([]prometheus.Metric, bool) { + connectionStatusDisable := prometheus.NewDesc( + "fortigate_sandbox_connection_status_disabled", + "Sandbox connection status", + []string{"sandbox_type"}, nil, + ) + connectionStatusUreachable := prometheus.NewDesc( + "fortigate_sandbox_connection_status_unreachable", + "Sandbox connection status", + []string{"sandbox_type"}, nil, + ) + connectionStatusReachable := prometheus.NewDesc( + "fortigate_sandbox_connection_status_reachable", + "Sandbox connection status", + []string{"sandbox_type"}, nil, + ) + + type SystemSandboxConnection struct { + Status string `json:"status"` + Type string `json:"type"` + } + + type SystemSandboxConnectionResult struct { + Results []SystemSandboxConnection `json:"results"` + } + var res SystemSandboxConnectionResult + if err := c.Get("api/v2/monitor/system/sandbox/connection", "", &res); err != nil { + log.Printf("Warning: %v", err) + return nil, false + } + + m := []prometheus.Metric{} + for _, r := range res.Results { + switch r.Status { + case "unreachable": + m = append(m, prometheus.MustNewConstMetric(connectionStatusUreachable, prometheus.GaugeValue, 1, r.Type)) + m = append(m, prometheus.MustNewConstMetric(connectionStatusReachable, prometheus.GaugeValue, 0, r.Type)) + m = append(m, prometheus.MustNewConstMetric(connectionStatusDisable, prometheus.GaugeValue, 0, r.Type)) + case "reachable": + m = append(m, prometheus.MustNewConstMetric(connectionStatusUreachable, prometheus.GaugeValue, 0, r.Type)) + m = append(m, prometheus.MustNewConstMetric(connectionStatusReachable, prometheus.GaugeValue, 1, r.Type)) + m = append(m, prometheus.MustNewConstMetric(connectionStatusDisable, prometheus.GaugeValue, 0, r.Type)) + case "disabled": + m = append(m, prometheus.MustNewConstMetric(connectionStatusUreachable, prometheus.GaugeValue, 0, r.Type)) + m = append(m, prometheus.MustNewConstMetric(connectionStatusReachable, prometheus.GaugeValue, 0, r.Type)) + m = append(m, prometheus.MustNewConstMetric(connectionStatusDisable, prometheus.GaugeValue, 1, r.Type)) + } + } + return m, true +} diff --git a/pkg/probe/system_sandbox_connection_test.go b/pkg/probe/system_sandbox_connection_test.go new file mode 100644 index 00000000..c21afb99 --- /dev/null +++ b/pkg/probe/system_sandbox_connection_test.go @@ -0,0 +1,47 @@ +// 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 TestSystemSandboxConnection(t *testing.T) { + c := newFakeClient() + c.prepare("api/v2/monitor/system/sandbox/connection", "testdata/system-sandbox-connection.jsonnet") + r := prometheus.NewPedanticRegistry() + if !testProbe(probeSystemSandboxConnection, c, r) { + t.Errorf("probeSystemSandboxConnection() returned non-success") + } + + em := ` + # HELP fortigate_sandbox_connection_status_disabled Sandbox connection status + # TYPE fortigate_sandbox_connection_status_disabled gauge + fortigate_sandbox_connection_status_disabled{sandbox_type="appliance"} 0 + # HELP fortigate_sandbox_connection_status_reachable Sandbox connection status + # TYPE fortigate_sandbox_connection_status_reachable gauge + fortigate_sandbox_connection_status_reachable{sandbox_type="appliance"} 1 + # HELP fortigate_sandbox_connection_status_unreachable Sandbox connection status + # TYPE fortigate_sandbox_connection_status_unreachable gauge + fortigate_sandbox_connection_status_unreachable{sandbox_type="appliance"} 0 + ` + + if err := testutil.GatherAndCompare(r, strings.NewReader(em)); err != nil { + t.Fatalf("metric compare: err %v", err) + } +} diff --git a/pkg/probe/system_sandbox_stats.go b/pkg/probe/system_sandbox_stats.go new file mode 100644 index 00000000..d48f1176 --- /dev/null +++ b/pkg/probe/system_sandbox_stats.go @@ -0,0 +1,87 @@ +// 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" + + "github.com/prometheus/client_golang/prometheus" + + "github.com/prometheus-community/fortigate_exporter/pkg/http" +) + +func probeSystemSandboxStats(c http.FortiHTTP, _ *TargetMetadata) ([]prometheus.Metric, bool) { + var ( + numberDetected = prometheus.NewDesc( + "fortigate_sandbox_stats_detected_total", + "Number of detected files", + []string{}, nil, + ) + numberClean = prometheus.NewDesc( + "fortigate_sandbox_stats_clean_total", + "Number of clean files", + []string{}, nil, + ) + numberRiskLow = prometheus.NewDesc( + "fortigate_sandbox_stats_risk_low_total", + "Number of low risk files detected", + []string{}, nil, + ) + numberRiskMedium = prometheus.NewDesc( + "fortigate_sandbox_stats_risk_medium_total", + "Number of medium risk files detected", + []string{}, nil, + ) + numberRiskHigh = prometheus.NewDesc( + "fortigate_sandbox_stats_risk_high_total", + "Number of high risk files detected", + []string{}, nil, + ) + numberSubmitted = prometheus.NewDesc( + "fortigate_sandbox_stats_submitted_total", + "Number of submitted files", + []string{}, nil, + ) + ) + + type SystemSandboxStats struct { + Detected float64 + Clean float64 + Low float64 `json:"risk_low"` + Medium float64 `json:"risk_med"` + High float64 `json:"risk_high"` + Submitted float64 + } + + type SystemSandboxStatsResult struct { + Results []SystemSandboxStats `json:"results"` + } + + var res SystemSandboxStatsResult + if err := c.Get("api/v2/monitor/system/sandbox/stats", "", &res); err != nil { + log.Printf("Warning: %v", err) + return nil, false + } + m := []prometheus.Metric{} + + for _, r := range res.Results { + m = append(m, prometheus.MustNewConstMetric(numberDetected, prometheus.CounterValue, r.Detected)) + m = append(m, prometheus.MustNewConstMetric(numberClean, prometheus.CounterValue, r.Clean)) + m = append(m, prometheus.MustNewConstMetric(numberRiskLow, prometheus.CounterValue, r.Low)) + m = append(m, prometheus.MustNewConstMetric(numberRiskMedium, prometheus.CounterValue, r.Medium)) + m = append(m, prometheus.MustNewConstMetric(numberRiskHigh, prometheus.CounterValue, r.High)) + m = append(m, prometheus.MustNewConstMetric(numberSubmitted, prometheus.CounterValue, r.Submitted)) + } + return m, true +} diff --git a/pkg/probe/system_sandbox_stats_test.go b/pkg/probe/system_sandbox_stats_test.go new file mode 100644 index 00000000..8ea573c2 --- /dev/null +++ b/pkg/probe/system_sandbox_stats_test.go @@ -0,0 +1,56 @@ +// 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 TestSystemSandboxStats(t *testing.T) { + c := newFakeClient() + c.prepare("api/v2/monitor/system/sandbox/stats", "testdata/system-sandbox-stats.jsonnet") + r := prometheus.NewPedanticRegistry() + if !testProbe(probeSystemSandboxStats, c, r) { + t.Errorf("probeSystemSandboxStats() returned non-success") + } + + em := ` + # HELP fortigate_sandbox_stats_clean_total Number of clean files + # TYPE fortigate_sandbox_stats_clean_total counter + fortigate_sandbox_stats_clean_total 45120 + # HELP fortigate_sandbox_stats_detected_total Number of detected files + # TYPE fortigate_sandbox_stats_detected_total counter + fortigate_sandbox_stats_detected_total 10 + # HELP fortigate_sandbox_stats_risk_high_total Number of high risk files detected + # TYPE fortigate_sandbox_stats_risk_high_total counter + fortigate_sandbox_stats_risk_high_total 5 + # HELP fortigate_sandbox_stats_risk_low_total Number of low risk files detected + # TYPE fortigate_sandbox_stats_risk_low_total counter + fortigate_sandbox_stats_risk_low_total 3 + # HELP fortigate_sandbox_stats_risk_medium_total Number of medium risk files detected + # TYPE fortigate_sandbox_stats_risk_medium_total counter + fortigate_sandbox_stats_risk_medium_total 2 + # HELP fortigate_sandbox_stats_submitted_total Number of submitted files + # TYPE fortigate_sandbox_stats_submitted_total counter + fortigate_sandbox_stats_submitted_total 45130 + ` + + if err := testutil.GatherAndCompare(r, strings.NewReader(em)); err != nil { + t.Fatalf("metric compare: err %v", err) + } +} diff --git a/pkg/probe/system_sandbox_status.go b/pkg/probe/system_sandbox_status.go new file mode 100644 index 00000000..089d7829 --- /dev/null +++ b/pkg/probe/system_sandbox_status.go @@ -0,0 +1,70 @@ +// 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 probeSystemSandboxStatus(c http.FortiHTTP, _ *TargetMetadata) ([]prometheus.Metric, bool) { + Count := prometheus.NewDesc( + "fortigate_system_sandbox_status_signatures_count", + "The number of signatures that have been loaded on the FortiSandbox.", + []string{"configured", "type", "cloud_region", "server", "malware_package_version", "signatures_loaded", "vdom"}, nil, + ) + + type SystemSandboxStatus struct { + Configured bool `json:"configured"` + Type string `json:"type"` + Cloud string `json:"cloud_region"` + Server string `json:"server"` + MPV string `json:"malware_package_version"` + Loaded bool `json:"signatures_loaded"` + Count float64 `json:"signatures_count"` + } + + type SystemSandboxStatusResult struct { + Result SystemSandboxStatus `json:"results"` + VDOM string `json:"vdom"` + } + + var res SystemSandboxStatusResult + if err := c.Get("api/v2/monitor/system/sandbox/status", "", &res); err != nil { + log.Printf("Warning: %v", err) + return nil, false + } + m := []prometheus.Metric{} + cloud := "null" + if res.Result.Cloud != "" { + cloud = res.Result.Cloud + } + m = append(m, prometheus.MustNewConstMetric( + Count, + prometheus.GaugeValue, + res.Result.Count, + strconv.FormatBool(res.Result.Configured), + res.Result.Type, + cloud, + res.Result.Server, + res.Result.MPV, + strconv.FormatBool(res.Result.Loaded), + res.VDOM), + ) + return m, true +} diff --git a/pkg/probe/system_sandbox_status_test.go b/pkg/probe/system_sandbox_status_test.go new file mode 100644 index 00000000..ac97be6e --- /dev/null +++ b/pkg/probe/system_sandbox_status_test.go @@ -0,0 +1,41 @@ +// 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 TestSandboxStatus(t *testing.T) { + c := newFakeClient() + c.prepare("api/v2/monitor/system/sandbox/status", "testdata/system-sandbox-status.jsonnet") + r := prometheus.NewPedanticRegistry() + if !testProbe(probeSystemSandboxStatus, c, r) { + t.Errorf("probeSystemSandboxStatus() returned non-success") + } + + em := ` + # HELP fortigate_system_sandbox_status_signatures_count The number of signatures that have been loaded on the FortiSandbox. + # TYPE fortigate_system_sandbox_status_signatures_count gauge + fortigate_system_sandbox_status_signatures_count{cloud_region="null",configured="true",malware_package_version="5.125",server="0.0.0.0",signatures_loaded="false",type="appliance",vdom="root"} 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-sandbox-connection.jsonnet b/pkg/probe/testdata/system-sandbox-connection.jsonnet new file mode 100644 index 00000000..9a4e238d --- /dev/null +++ b/pkg/probe/testdata/system-sandbox-connection.jsonnet @@ -0,0 +1,18 @@ +# api/v2/monitor/system/sandbox/connection +{ + "http_method":"GET", + "results":[ + { + "status": "reachable", + "type": "appliance" + } + ], + "vdom":"google", + "path":"system", + "name":"sdn-connector", + "action":"status", + "status":"success", + "serial":"FGABCDEF12345678", + "version":"v7.0.9", + "build":444 +} diff --git a/pkg/probe/testdata/system-sandbox-stats.jsonnet b/pkg/probe/testdata/system-sandbox-stats.jsonnet new file mode 100644 index 00000000..ee333583 --- /dev/null +++ b/pkg/probe/testdata/system-sandbox-stats.jsonnet @@ -0,0 +1,22 @@ +# api/v2/monitor/system/sandbox/stats +{ + "http_method":"GET", + "results":[ + { + "detected": 10, + "clean": 45120, + "risk_low": 3, + "risk_med": 2, + "risk_high": 5, + "submitted": 45130 + } + ], + "vdom":"google", + "path":"system", + "name":"sdn-connector", + "action":"status", + "status":"success", + "serial":"FGABCDEF12345678", + "version":"v7.0.9", + "build":444 +} diff --git a/pkg/probe/testdata/system-sandbox-status.jsonnet b/pkg/probe/testdata/system-sandbox-status.jsonnet new file mode 100644 index 00000000..222d4149 --- /dev/null +++ b/pkg/probe/testdata/system-sandbox-status.jsonnet @@ -0,0 +1,20 @@ +{ + "http_method":"GET", + "results": { + "configured":true, + "type":"appliance", + "cloud_region":"", + "server":"0.0.0.0", + "malware_package_version":"5.125", + "signatures_loaded":false, + "signatures_count":0 + }, + "vdom":"root", + "path":"system", + "name":"sandbox", + "action":"status", + "status":"success", + "serial":"g43sags54rh5es", + "version":"v7.4.8", + "build":2795 +} \ No newline at end of file