forked from firedancer-io/radiance
/
app.go
150 lines (124 loc) · 4.13 KB
/
app.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package main
import (
"context"
"flag"
"net"
"net/http"
_ "net/http/pprof"
"os"
"os/signal"
"path"
"syscall"
"time"
"github.com/coreos/go-systemd/v22/activation"
"github.com/prometheus/client_golang/prometheus/promhttp"
metrics "github.com/slok/go-http-metrics/metrics/prometheus"
"github.com/slok/go-http-metrics/middleware"
"github.com/slok/go-http-metrics/middleware/std"
"golang.org/x/crypto/acme"
"golang.org/x/crypto/acme/autocert"
"k8s.io/klog/v2"
"go.firedancer.io/radiance/pkg/util"
)
var (
backendAddr = flag.String("backend", "http://127.0.0.1:8899", "Backend RPC URI to proxy to")
debugAddr = flag.String("listen", "[::1]:6060", "pprof and metrics server address")
tlsHostname = flag.String("tlsHostname", "", "When set, serve TLS using Let's Encrypt using the hostname in question")
tlsProd = flag.Bool("tlsProd", false, "Use the production Let's Encrypt environment")
cacheDir = flag.String("cacheDir", "solrays-data", "Cache directory")
)
func init() {
klog.CopyStandardLogTo("INFO")
klog.InitFlags(nil)
flag.Parse()
}
func getSDListeners() []net.Listener {
// We use systemd socket activation for (almost) zero downtime deployment -
// systemd will keep the socket open even while we restart the process
// (plus, it allows us to bind to port 80).
//
// Read more: https://vincent.bernat.ch/en/blog/2018-systemd-golang-socket-activation
listeners, err := activation.Listeners()
if err != nil {
klog.Fatalf("cannot retrieve listeners: %s", err)
}
if len(listeners) != 1 {
klog.Fatalf("unexpected number of sockets passed by systemd (%d != 1)", len(listeners))
}
return listeners
}
func shutdownHandler(server *http.Server) chan struct{} {
done := make(chan struct{})
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-quit
klog.Info("server is shutting down")
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
server.SetKeepAlivesEnabled(false)
if err := server.Shutdown(ctx); err != nil {
klog.Exitf("cannot gracefully shut down the server: %s", err)
}
close(done)
}()
return done
}
func main() {
listeners := getSDListeners()
// Metrics recording middleware
mdlw := middleware.New(middleware.Config{
Recorder: metrics.NewRecorder(metrics.Config{}),
})
mux := http.NewServeMux()
mux.Handle("/", newHandler())
mux.HandleFunc("/health", func(w http.ResponseWriter, req *http.Request) {
klog.V(1).Infof("[%s] %s %s %v", req.RemoteAddr, req.Method, req.URL, req.Header)
w.Write([]byte("ok"))
})
wrapped := std.Handler("default", mdlw, mux)
server := &http.Server{
Handler: wrapped,
ReadTimeout: readTimeout,
WriteTimeout: requestTimeout,
}
// Setup TLS if an hostname has been specified.
if *tlsHostname != "" {
// Proceed only if a valid hostname has been specified.
if util.IsValidHostname(*tlsHostname) {
klog.Fatalf("tlsHostname [%s] is an invalid hostname, exiting", *tlsHostname)
}
klog.Infof("provisioning Let's Encrypt certificate for %s", *tlsHostname)
var acmeApi string
if *tlsProd {
klog.Infof("using production Let's Encrypt server")
acmeApi = autocert.DefaultACMEDirectory
} else {
klog.Infof("using staging Let's Encrypt server")
acmeApi = "https://acme-staging-v02.api.letsencrypt.org/directory"
}
certManager := autocert.Manager{
Prompt: autocert.AcceptTOS,
HostPolicy: autocert.HostWhitelist(*tlsHostname),
Cache: autocert.DirCache(path.Join(*cacheDir, "autocert")),
Client: &acme.Client{DirectoryURL: acmeApi},
}
server.TLSConfig = certManager.TLSConfig()
klog.Info("certificate provisioning configured")
}
// Graceful shutdown
done := shutdownHandler(server)
go func() {
http.Handle("/metrics", promhttp.Handler())
klog.Infof("debug server listening on %s", *debugAddr)
klog.Exit(http.ListenAndServe(*debugAddr, nil))
}()
if *tlsHostname != "" {
klog.Infof("main server listening with TLS on %s", listeners[0].Addr())
klog.Exit(server.ServeTLS(listeners[0], "", ""))
} else {
klog.Infof("main server listening on %s", listeners[0].Addr())
klog.Exit(server.Serve(listeners[0]))
}
<-done
}