Skip to content

Commit

Permalink
set up healthy and reload endpoints
Browse files Browse the repository at this point in the history
* `/-/healthy` indicates that the http server successfully started, and
  consequentially the config was successfully parsed.
* `/-/reload` allows to attempt to reload the config, which is expected
  to be called by a sidecar that watches for config file changes

Signed-off-by: Carlos Rodriguez-Fernandez <[email protected]>
  • Loading branch information
carlosrodfern committed Mar 29, 2024
1 parent a22a294 commit c2529c1
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 2 deletions.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ In each host group the `interval`, `network`, and `protocol` are optional.

The interval Duration is in [Go time.ParseDuration()](https://golang.org/pkg/time/#ParseDuration) syntax.

The config is read on startup, and can be reloaded with the SIGHUP signal.
The config is read on startup, and can be reloaded with the SIGHUP signal, or with an HTTP POST to the URI path `/-/reload`.

## Building and running

Expand Down Expand Up @@ -100,3 +100,8 @@ The Smokeping Prober supports TLS and basic authentication.
To use TLS and/or basic authentication, you need to pass a configuration file
using the `--web.config.file` parameter. The format of the file is described
[in the exporter-toolkit repository](https://github.com/prometheus/exporter-toolkit/blob/master/docs/web-configuration.md).


### Health check

A health check can be requested in the URI path `/-/healthy`.
38 changes: 37 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,31 +264,67 @@ func main() {

hup := make(chan os.Signal, 1)
signal.Notify(hup, syscall.SIGHUP)
reloadCh := make(chan chan error)
go func() {
for {
<-hup
var errCallback func(e error)
var successCallback func()
select {
case <-hup:
errCallback = func(e error) {}
successCallback = func() {}
case rc := <-reloadCh:
errCallback = func(e error) {
rc <- e
}
successCallback = func() {
rc <- nil
}
}
if err := sc.ReloadConfig(*configFile); err != nil {
level.Error(logger).Log("msg", "Error reloading config", "err", err)
errCallback(err)
continue
}
err = smokePingers.prepare(hosts, interval, privileged, sizeBytes)
if err != nil {
level.Error(logger).Log("msg", "Unable to create ping from config", "err", err)
errCallback(err)
continue
}
if smokePingers.sizeOfPrepared() == 0 {
level.Error(logger).Log("msg", "No targets specified on command line or in config file")
errCallback(fmt.Errorf("no targets specified"))
continue
}

smokePingers.start()
smokepingCollector.updatePingers(smokePingers.started, *pingResponseSeconds)

level.Info(logger).Log("msg", "Reloaded config file")
successCallback()
}
}()

http.Handle(*metricsPath, promhttp.Handler())
http.HandleFunc("/-/healthy", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("Healthy"))
})
http.HandleFunc("/-/reload",
func(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
w.WriteHeader(http.StatusMethodNotAllowed)
fmt.Fprintf(w, "This endpoint requires a POST request.\n")
return
}

rc := make(chan error)
reloadCh <- rc
if err := <-rc; err != nil {
http.Error(w, fmt.Sprintf("Failed to reload config: %s", err), http.StatusInternalServerError)
}
})
if *metricsPath != "/" && *metricsPath != "" {
landingConfig := web.LandingConfig{
Name: "Smokeping Prober",
Expand Down

0 comments on commit c2529c1

Please sign in to comment.