--- /dev/null
+package main
+
+import (
+ "context"
+ "encoding/json"
+ "flag"
+ "fmt"
+ "net/http"
+ "os/signal"
+ "sync"
+ "syscall"
+ "time"
+
+ "github.com/coreos/go-systemd/daemon"
+
+ "go.fuhry.dev/runtime/constants"
+ "go.fuhry.dev/runtime/mtls"
+ "go.fuhry.dev/runtime/sd"
+ "go.fuhry.dev/runtime/utils/log"
+)
+
+type endpoint struct {
+ Targets []string `json:"targets"`
+ Labels map[string]string `json:"labels"`
+}
+
+func main() {
+ mtls.SetDefaultIdentity("node-exporter")
+ ctx, _ := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
+ serverCtx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ port := flag.Uint("port", 9102, "port to listen on")
+
+ flag.Parse()
+
+ id := mtls.DefaultIdentity()
+ tlsConfig, err := id.TlsConfig(serverCtx)
+ if err != nil {
+ log.Panic(err)
+ }
+ pv := mtls.NewPeerNameVerifier()
+ pv.AllowFrom(mtls.Service, "prometheus")
+ pv.AllowFrom(mtls.Service, "healthcheck")
+ err = pv.ConfigureServer(tlsConfig)
+ if err != nil {
+ log.Panic(err)
+ }
+
+ mux := http.NewServeMux()
+ loggingMiddleware := log.NewLoggingMiddleware(mux)
+ sdWatchers := make(map[string]*sd.SDWatcher, 0)
+ sdLock := sync.Mutex{}
+ mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ w.Write([]byte(fmt.Sprintf("<h1>%s Prometheus HTTP discovery servicer</h1>", constants.OrgName)))
+ })
+ mux.HandleFunc("/endpoints/{service}", func(w http.ResponseWriter, r *http.Request) {
+ service := r.PathValue("service")
+ sdLock.Lock()
+ if _, ok := sdWatchers[service]; !ok {
+ sdWatchers[service] = &sd.SDWatcher{
+ Service: service,
+ Protocol: sd.ProtocolTCP,
+ }
+ }
+ watcher := sdWatchers[service]
+ sdLock.Unlock()
+
+ endpoints, err := watcher.GetAddrs(serverCtx)
+ if err != nil {
+ w.WriteHeader(http.StatusInternalServerError)
+ w.Write([]byte(err.Error()))
+ return
+ }
+
+ targets := make([]*endpoint, 0)
+ for _, ep := range endpoints {
+ targets = append(targets, &endpoint{
+ Targets: []string{
+ fmt.Sprintf("%s:%d", ep.Hostname, ep.Port),
+ },
+ Labels: map[string]string{
+ "shard": ep.Shard,
+ "host": ep.Hostname,
+ },
+ })
+ }
+
+ out, err := json.MarshalIndent(targets, "", " ")
+ if err != nil {
+ w.WriteHeader(http.StatusInternalServerError)
+ w.Write([]byte(err.Error()))
+ return
+ }
+ w.Header().Set("content-type", "application/json")
+
+ w.Write(out)
+ })
+ server := &http.Server{
+ Addr: fmt.Sprintf("[::1]:%d", *port),
+ TLSConfig: tlsConfig,
+ Handler: loggingMiddleware.HandlerFunc(),
+ }
+
+ go server.ListenAndServeTLS("", "")
+
+ daemon.SdNotify(false, daemon.SdNotifyReady)
+
+ <-ctx.Done()
+ cancel()
+
+ shutdownCtx, _ := context.WithTimeout(context.Background(), 5*time.Second)
+ server.Shutdown(shutdownCtx)
+}