diff --git a/main.go b/main.go index 07a6fe0..d8c5326 100644 --- a/main.go +++ b/main.go @@ -1,59 +1,92 @@ -// Copyright 2017 Kumina, https://kumina.nl/ -// 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 main import ( - "flag" - "github.com/kumina/openvpn_exporter/exporters" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promhttp" - "log" - "net/http" - "strings" +// "bytes" + "flag" + "fmt" + "github.com/kumina/openvpn_exporter/exporters" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" + "log" + "net/http" + "os/exec" + "strings" + "time" ) +var serviceOpenVPN = prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "service_openvpn", + Help: "Indicates whether the OpenVPN service is up (1) or down (0).", +}) + func main() { - var ( - listenAddress = flag.String("web.listen-address", ":9176", "Address to listen on for web interface and telemetry.") - metricsPath = flag.String("web.telemetry-path", "/metrics", "Path under which to expose metrics.") - openvpnStatusPaths = flag.String("openvpn.status_paths", "examples/client.status,examples/server2.status,examples/server3.status", "Paths at which OpenVPN places its status files.") - ignoreIndividuals = flag.Bool("ignore.individuals", false, "If ignoring metrics for individuals") - ) - flag.Parse() + var ( + listenAddress = flag.String("web.listen-address", ":9176", "Address to listen on for web interface and telemetry.") + metricsPath = flag.String("web.telemetry-path", "/metrics", "Path under which to expose metrics.") + openvpnStatusPaths = flag.String("openvpn.status_paths", "/var/log/openvpn-status.log", "Paths at which OpenVPN places its status files.") + ignoreIndividuals = flag.Bool("ignore.individuals", false, "If ignoring metrics for individuals.") + ) + flag.Parse() - log.Printf("Starting OpenVPN Exporter\n") - log.Printf("Listen address: %v\n", *listenAddress) - log.Printf("Metrics path: %v\n", *metricsPath) - log.Printf("openvpn.status_path: %v\n", *openvpnStatusPaths) - log.Printf("Ignore Individuals: %v\n", *ignoreIndividuals) + log.Printf("Starting OpenVPN Exporter\n") + log.Printf("Listen address: %v\n", *listenAddress) + log.Printf("Metrics path: %v\n", *metricsPath) + log.Printf("openvpn.status_path: %v\n", *openvpnStatusPaths) + log.Printf("Ignore Individuals: %v\n", *ignoreIndividuals) - exporter, err := exporters.NewOpenVPNExporter(strings.Split(*openvpnStatusPaths, ","), *ignoreIndividuals) - if err != nil { - panic(err) - } - prometheus.MustRegister(exporter) + exporter, err := exporters.NewOpenVPNExporter(strings.Split(*openvpnStatusPaths, ","), *ignoreIndividuals) + if err != nil { + panic(err) + } + prometheus.MustRegister(exporter) + prometheus.MustRegister(serviceOpenVPN) - http.Handle(*metricsPath, promhttp.Handler()) - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(` - - OpenVPN Exporter - -

OpenVPN Exporter

-

Metrics

- - `)) - }) - log.Fatal(http.ListenAndServe(*listenAddress, nil)) + go updateOpenVPNServiceStatus() + + http.Handle(*metricsPath, promhttp.Handler()) + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(` + + OpenVPN Exporter + +

OpenVPN Exporter

+

Metrics

+ + `)) + }) + log.Fatal(http.ListenAndServe(*listenAddress, nil)) +} + +func updateOpenVPNServiceStatus() { + for { + isActive, err := isServiceActive("openvpn") + if err != nil { + log.Printf("Error checking OpenVPN service status: %v", err) + } else { + if isActive { + serviceOpenVPN.Set(1) + } else { + serviceOpenVPN.Set(0) + } + } + time.Sleep(5 * time.Second) + } +} + +func isServiceActive(serviceName string) (bool, error) { + cmd := exec.Command("systemctl", "is-active", "--quiet", serviceName) + + // Run the command without capturing output + if err := cmd.Run(); err != nil { + // Check if exit status is 3 (unknown) and treat it as inactive + if exitError, ok := err.(*exec.ExitError); ok { + if status, ok := exitError.Sys().(syscall.WaitStatus); ok && status.ExitStatus() == 3 { + return false, nil + } + } + + return false, fmt.Errorf("failed to check service status: %v", err) + } + + return true, nil }