blob: 9569ee549116e3b0d836a1a142ddef5231f1946a [file] [log] [blame]
Sergiusz Bazanskie08e6da2018-08-27 20:40:10 +01001package main
2
3import (
4 "context"
5 "crypto/tls"
6 "crypto/x509"
7 "fmt"
8 "io/ioutil"
9 "net"
10 "net/http"
11
Sergiusz Bazanskif9d85cf2018-08-28 14:13:36 +010012 "code.hackerspace.pl/q3k/hspki"
Sergiusz Bazanskie08e6da2018-08-27 20:40:10 +010013 "github.com/golang/glog"
14 "github.com/q3k/statusz"
15 "golang.org/x/net/trace"
16 "google.golang.org/grpc"
17 "google.golang.org/grpc/credentials"
18 "google.golang.org/grpc/reflection"
19
20 pb "code.hackerspace.pl/q3k/arista-proxy/proto"
21)
22
23type serverOpts struct {
24 listenAddress string
25 debugAddress string
26 tlsCAPath string
27 tlsCertificatePath string
28 tlsKeyPath string
Sergiusz Bazanskie08e6da2018-08-27 20:40:10 +010029}
30
31type server struct {
32 arista *aristaClient
33 opts *serverOpts
34
35 grpc struct {
36 listen net.Listener
37 server *grpc.Server
38 }
39 http struct {
40 listen net.Listener
41 server *http.Server
42 }
43}
44
45func newServer(opts *serverOpts, arista *aristaClient) (*server, error) {
46 return &server{
47 opts: opts,
48 arista: arista,
49 }, nil
50}
51
52func (s *server) trace(ctx context.Context, f string, args ...interface{}) {
53 tr, ok := trace.FromContext(ctx)
54 if !ok {
55 fmtd := fmt.Sprintf(f, args...)
56 glog.Warningf("No trace in %v: %s", ctx, fmtd)
57 return
58 }
59 tr.LazyPrintf(f, args...)
60}
61
62func (s *server) setupGRPC(options ...grpc.ServerOption) error {
63 serverCert, err := tls.LoadX509KeyPair(s.opts.tlsCertificatePath, s.opts.tlsKeyPath)
64 if err != nil {
65 return fmt.Errorf("while loading keypair: %v", err)
66 }
67
68 certPool := x509.NewCertPool()
69 ca, err := ioutil.ReadFile(s.opts.tlsCAPath)
70 if err != nil {
71 return fmt.Errorf("while loading ca certificate: %v", err)
72 }
73 if ok := certPool.AppendCertsFromPEM(ca); !ok {
74 return fmt.Errorf("while appending ca certificate to pool: %v", err)
75 }
76
77 lis, err := net.Listen("tcp", s.opts.listenAddress)
78 if err != nil {
79 return fmt.Errorf("while listening on main port: %v", err)
80 }
81
82 creds := credentials.NewTLS(&tls.Config{
83 ClientAuth: tls.RequireAndVerifyClientCert,
84 Certificates: []tls.Certificate{serverCert},
85 ClientCAs: certPool,
86 })
87
88 s.grpc.listen = lis
89 options = append([]grpc.ServerOption{grpc.Creds(creds)}, options...)
90 s.grpc.server = grpc.NewServer(options...)
91
92 return nil
93}
94
95func (s *server) setupDebugHTTP(mux http.Handler) error {
96 lis, err := net.Listen("tcp", s.opts.debugAddress)
97 if err != nil {
98 return fmt.Errorf("while listening on main port: %v", err)
99 }
100
101 s.http.listen = lis
102 s.http.server = &http.Server{
103 Addr: s.opts.debugAddress,
104 Handler: mux,
105 }
106
107 return nil
108}
109
110func (s *server) serveForever() {
111 grpc.EnableTracing = true
112
Sergiusz Bazanskif9d85cf2018-08-28 14:13:36 +0100113 if err := s.setupGRPC(hspki.WithServerHSPKI()); err != nil {
Sergiusz Bazanskie08e6da2018-08-27 20:40:10 +0100114 glog.Exitf("Could not setup GRPC server: %v", err)
115 }
116 pb.RegisterAristaProxyServer(s.grpc.server, s)
117 reflection.Register(s.grpc.server)
118
119 go func() {
120 if err := s.grpc.server.Serve(s.grpc.listen); err != nil {
121 glog.Exitf("Could not start GRPC server: %v", err)
122 }
123 }()
124 glog.Infof("Listening for GRPC on %v", s.opts.listenAddress)
125
Sergiusz Bazanskib27d5282018-08-27 21:07:23 +0100126 if s.opts.debugAddress == "" {
127 glog.Info("Disabling debug HTTP server")
128 } else {
129 httpMux := http.NewServeMux()
130 httpMux.HandleFunc("/debug/status", statusz.StatusHandler)
131 httpMux.HandleFunc("/debug/requests", trace.Traces)
132 httpMux.HandleFunc("/", statusz.StatusHandler)
Sergiusz Bazanskie08e6da2018-08-27 20:40:10 +0100133
Sergiusz Bazanskib27d5282018-08-27 21:07:23 +0100134 if err := s.setupDebugHTTP(httpMux); err != nil {
135 glog.Exitf("Could not setup HTTP server: %v", err)
Sergiusz Bazanskie08e6da2018-08-27 20:40:10 +0100136 }
Sergiusz Bazanskib27d5282018-08-27 21:07:23 +0100137
138 go func() {
139 if err := s.http.server.Serve(s.http.listen); err != nil {
140 glog.Exitf("Could not start HTTP server: %v", err)
141 }
142 }()
143 glog.Infof("Listening for HTTP on %v", s.opts.debugAddress)
144 }
Sergiusz Bazanskie08e6da2018-08-27 20:40:10 +0100145
146 select {}
147}