Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package main
- import (
- "fmt"
- "log"
- "os"
- "strings"
- "crypto/tls"
- "time"
- "math"
- "net/http"
- "github.com/prometheus/client_golang/prometheus"
- "github.com/prometheus/client_golang/prometheus/promhttp"
- )
- var (
- connErrs = prometheus.NewGaugeVec(
- prometheus.GaugeOpts{
- Name: "host_connection_error",
- Help: "Boolean connection error indicator",
- },
- []string{"host"},
- )
- certExpiry = prometheus.NewGaugeVec(
- prometheus.GaugeOpts{
- Name: "cert_expiry_in_seconds",
- Help: "Seconds left to certificate expiry in chain (can be CA)",
- },
- []string{"host", "cn"},
- )
- )
- type HostnameChan chan string
- func hostChecker(hostChan HostnameChan) {
- defer func() {
- if hostChan != nil {
- close(hostChan)
- }
- }()
- for {
- if hostChan == nil { return } // quit if the channel is dereferenced
- select {
- case host := <- hostChan:
- next_expiry, selected_cert := getCertExpiry(host)
- log.Printf("%s (%s): %f hours\n", host, selected_cert, next_expiry / 60 / 60)
- }
- }
- }
- func getCertExpiry(host string) (float64, string) {
- now := time.Now()
- conf := &tls.Config{
- InsecureSkipVerify: true,
- }
- next_expiry := math.MaxFloat64
- selected_cert := "none"
- conn, err := tls.Dial("tcp", host, conf)
- if err != nil {
- log.Println(err)
- connErrs.With(prometheus.Labels{"host": host}).Set(1)
- return next_expiry, selected_cert
- }
- defer conn.Close()
- for _, cert := range conn.ConnectionState().PeerCertificates {
- seconds_left := cert.NotAfter.Sub(now).Seconds()
- if seconds_left < next_expiry {
- selected_cert = cert.Subject.CommonName
- next_expiry = seconds_left
- }
- }
- connErrs.With(prometheus.Labels{"host": host}).Set(0)
- certExpiry.With(prometheus.Labels{"host": host, "cn": selected_cert}).Set(next_expiry)
- return next_expiry, selected_cert
- }
- func makeRegistry() *prometheus.Registry {
- r := prometheus.NewRegistry()
- r.MustRegister(connErrs)
- r.MustRegister(certExpiry)
- return r
- }
- func checkAll(hostChan HostnameChan, hosts []string) {
- for _, host := range hosts {
- hostChan <- host
- }
- }
- func parseTimerConfig(defaultDuration time.Duration) time.Duration {
- fromConfig := os.Getenv("CHK_INTERVAL")
- if fromConfig == "" {
- log.Printf("No CHK_INTERVAL given. Using default.\n", defaultDuration.Minutes())
- return defaultDuration
- }
- duration, err := time.ParseDuration(fromConfig)
- if err != nil {
- log.Printf("Error parsing CHK_INTERVAL value: '%s'. Using default.\n", fromConfig)
- log.Println(err)
- return defaultDuration
- }
- if duration.Minutes() < 1 {
- log.Printf("Error: CHK_INTERVAL must be >= 1, given: %v. Using default", duration)
- return defaultDuration
- }
- return duration
- }
- func main() {
- fmt.Print(`
- _ _ _
- | | | | | |
- ___ ___ _ __| |_ ___| |__ ___ ___| | __
- / __/ _ \ '__| __/ __| '_ \ / _ \/ __| |/ /
- | (_| __/ | | || (__| | | | __/ (__| <
- \___\___|_| \__\___|_| |_|\___|\___|_|\_\
- `)
- r := makeRegistry()
- envHosts := os.Getenv("HOSTS")
- if envHosts == "" {
- log.Fatal("No hosts given")
- }
- hosts := strings.Split(envHosts, ",")
- log.Printf("Got hosts: %s\n", strings.Join(hosts, " "))
- if len(hosts) < 1 {
- log.Fatal("No hosts given")
- }
- defaultTickerInterval, err := time.ParseDuration("15m")
- if err != nil {
- log.Fatal(err)
- }
- tickerInterval := parseTimerConfig(defaultTickerInterval)
- log.Printf("Ticker interval: %v", tickerInterval)
- // checker
- hostChan := make(HostnameChan)
- go hostChecker(hostChan)
- // initial run
- checkAll(hostChan, hosts)
- // timer
- ticker := time.NewTicker(tickerInterval)
- go func() {
- for {
- select {
- case t := <-ticker.C:
- log.Printf("TICK! running checks... %d\n", t)
- checkAll(hostChan, hosts)
- }
- }
- }()
- http.Handle("/metrics", promhttp.HandlerFor(r, promhttp.HandlerOpts{}))
- log.Fatal(http.ListenAndServe(":8080", nil))
- }
Advertisement
Add Comment
Please, Sign In to add comment