blob: 4a5f01f3404f6216e625dd984e2acc8b4900784d [file] [log] [blame]
Serge Bazanski3fd70d82018-10-14 08:12:46 -07001package mirko
2
3import (
Serge Bazanskiaa81aa22018-10-14 08:36:05 -07004 "context"
Serge Bazanski3fd70d82018-10-14 08:12:46 -07005 "flag"
6 "fmt"
7 "net"
8 "net/http"
9 "time"
10
11 "code.hackerspace.pl/q3k/hspki"
12 "github.com/golang/glog"
13 "github.com/q3k/statusz"
14 "golang.org/x/net/trace"
15 "google.golang.org/grpc"
16 "google.golang.org/grpc/reflection"
17)
18
19var (
20 flagListenAddress string
21 flagDebugAddress string
22)
23
24func init() {
Serge Bazanski69de9cb2018-10-14 08:49:04 -070025 flag.StringVar(&flagListenAddress, "listen_address", "127.0.0.1:4200", "gRPC listen address")
26 flag.StringVar(&flagDebugAddress, "debug_address", "127.0.0.1:4201", "HTTP debug/status listen address")
Serge Bazanskiaa81aa22018-10-14 08:36:05 -070027 flag.Set("logtostderr", "true")
Serge Bazanski3fd70d82018-10-14 08:12:46 -070028}
29
30type Mirko struct {
31 grpcListen net.Listener
32 grpcServer *grpc.Server
33 httpListen net.Listener
34 httpServer *http.Server
35 httpMux *http.ServeMux
36}
37
38func New() *Mirko {
39 return &Mirko{}
40}
41
42func (m *Mirko) Listen() error {
43 grpc.EnableTracing = true
44 grpcLis, err := net.Listen("tcp", flagListenAddress)
45 if err != nil {
46 return fmt.Errorf("net.Listen: %v", err)
47 }
48 m.grpcListen = grpcLis
49 m.grpcServer = grpc.NewServer(hspki.WithServerHSPKI()...)
50 reflection.Register(m.grpcServer)
51
52 httpLis, err := net.Listen("tcp", flagDebugAddress)
53 if err != nil {
54 return fmt.Errorf("net.Listen: %v", err)
55 }
56
57 m.httpMux = http.NewServeMux()
58 // Canonical URLs
59 m.httpMux.HandleFunc("/debug/status", statusz.StatusHandler)
60 m.httpMux.HandleFunc("/debug/requests", trace.Traces)
61
62 // -z legacy URLs
63 m.httpMux.HandleFunc("/statusz", func(w http.ResponseWriter, r *http.Request) {
64 http.Redirect(w, r, "/debug/status", http.StatusSeeOther)
65 })
66 m.httpMux.HandleFunc("/rpcz", func(w http.ResponseWriter, r *http.Request) {
67 http.Redirect(w, r, "/debug/requests", http.StatusSeeOther)
68 })
69 m.httpMux.HandleFunc("/requestz", func(w http.ResponseWriter, r *http.Request) {
70 http.Redirect(w, r, "/debug/requests", http.StatusSeeOther)
71 })
72
73 // root redirect
74 m.httpMux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
75 http.Redirect(w, r, "/debug/status", http.StatusSeeOther)
76 })
77
78 m.httpListen = httpLis
79 m.httpServer = &http.Server{
80 Addr: flagDebugAddress,
81 Handler: m.httpMux,
82 }
83
84 return nil
85}
86
Serge Bazanskiaa81aa22018-10-14 08:36:05 -070087func (m *Mirko) Trace(ctx context.Context, f string, args ...interface{}) {
88 tr, ok := trace.FromContext(ctx)
89 if !ok {
90 fmtd := fmt.Sprintf(f, args...)
91 glog.Warningf("No trace in %v: %s", ctx, fmtd)
92 return
93 }
94 tr.LazyPrintf(f, args...)
95}
96
Serge Bazanski3fd70d82018-10-14 08:12:46 -070097func (m *Mirko) GRPC() *grpc.Server {
98 if m.grpcServer == nil {
99 panic("GRPC() called before Listen()")
100 }
101 return m.grpcServer
102}
103
104func (m *Mirko) HTTPMux() *http.ServeMux {
105 if m.httpMux == nil {
106 panic("HTTPMux() called before Listen()")
107 }
108 return m.httpMux
109}
110
111func (m *Mirko) Serve() error {
112 errs := make(chan error, 1)
113 go func() {
114 if err := m.grpcServer.Serve(m.grpcListen); err != nil {
115 errs <- err
116 }
117 }()
118 go func() {
119 if err := m.httpServer.Serve(m.httpListen); err != nil {
120 errs <- err
121 }
122 }()
123
124 ticker := time.NewTicker(1 * time.Second)
125 select {
126 case <-ticker.C:
127 glog.Infof("gRPC listening on %s", flagListenAddress)
128 glog.Infof("HTTP listening on %s", flagDebugAddress)
129 return nil
130 case err := <-errs:
131 return err
132 }
133}