forked from hswaw/hscloud
144 lines
3.3 KiB
Go
144 lines
3.3 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"crypto/x509"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net"
|
|
"net/http"
|
|
|
|
"github.com/golang/glog"
|
|
"github.com/q3k/statusz"
|
|
"golang.org/x/net/trace"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/credentials"
|
|
"google.golang.org/grpc/reflection"
|
|
|
|
pb "code.hackerspace.pl/q3k/arista-proxy/proto"
|
|
)
|
|
|
|
type serverOpts struct {
|
|
listenAddress string
|
|
debugAddress string
|
|
tlsCAPath string
|
|
tlsCertificatePath string
|
|
tlsKeyPath string
|
|
pkiRealm string
|
|
}
|
|
|
|
type server struct {
|
|
arista *aristaClient
|
|
opts *serverOpts
|
|
|
|
grpc struct {
|
|
listen net.Listener
|
|
server *grpc.Server
|
|
}
|
|
http struct {
|
|
listen net.Listener
|
|
server *http.Server
|
|
}
|
|
}
|
|
|
|
func newServer(opts *serverOpts, arista *aristaClient) (*server, error) {
|
|
return &server{
|
|
opts: opts,
|
|
arista: arista,
|
|
}, nil
|
|
}
|
|
|
|
func (s *server) trace(ctx context.Context, f string, args ...interface{}) {
|
|
tr, ok := trace.FromContext(ctx)
|
|
if !ok {
|
|
fmtd := fmt.Sprintf(f, args...)
|
|
glog.Warningf("No trace in %v: %s", ctx, fmtd)
|
|
return
|
|
}
|
|
tr.LazyPrintf(f, args...)
|
|
}
|
|
|
|
func (s *server) setupGRPC(options ...grpc.ServerOption) error {
|
|
serverCert, err := tls.LoadX509KeyPair(s.opts.tlsCertificatePath, s.opts.tlsKeyPath)
|
|
if err != nil {
|
|
return fmt.Errorf("while loading keypair: %v", err)
|
|
}
|
|
|
|
certPool := x509.NewCertPool()
|
|
ca, err := ioutil.ReadFile(s.opts.tlsCAPath)
|
|
if err != nil {
|
|
return fmt.Errorf("while loading ca certificate: %v", err)
|
|
}
|
|
if ok := certPool.AppendCertsFromPEM(ca); !ok {
|
|
return fmt.Errorf("while appending ca certificate to pool: %v", err)
|
|
}
|
|
|
|
lis, err := net.Listen("tcp", s.opts.listenAddress)
|
|
if err != nil {
|
|
return fmt.Errorf("while listening on main port: %v", err)
|
|
}
|
|
|
|
creds := credentials.NewTLS(&tls.Config{
|
|
ClientAuth: tls.RequireAndVerifyClientCert,
|
|
Certificates: []tls.Certificate{serverCert},
|
|
ClientCAs: certPool,
|
|
})
|
|
|
|
s.grpc.listen = lis
|
|
options = append([]grpc.ServerOption{grpc.Creds(creds)}, options...)
|
|
s.grpc.server = grpc.NewServer(options...)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *server) setupDebugHTTP(mux http.Handler) error {
|
|
lis, err := net.Listen("tcp", s.opts.debugAddress)
|
|
if err != nil {
|
|
return fmt.Errorf("while listening on main port: %v", err)
|
|
}
|
|
|
|
s.http.listen = lis
|
|
s.http.server = &http.Server{
|
|
Addr: s.opts.debugAddress,
|
|
Handler: mux,
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *server) serveForever() {
|
|
grpc.EnableTracing = true
|
|
|
|
if err := s.setupGRPC(grpc.UnaryInterceptor(s.unaryInterceptor)); err != nil {
|
|
glog.Exitf("Could not setup GRPC server: %v", err)
|
|
}
|
|
pb.RegisterAristaProxyServer(s.grpc.server, s)
|
|
reflection.Register(s.grpc.server)
|
|
|
|
go func() {
|
|
if err := s.grpc.server.Serve(s.grpc.listen); err != nil {
|
|
glog.Exitf("Could not start GRPC server: %v", err)
|
|
}
|
|
}()
|
|
glog.Infof("Listening for GRPC on %v", s.opts.listenAddress)
|
|
|
|
httpMux := http.NewServeMux()
|
|
httpMux.HandleFunc("/debug/status", statusz.StatusHandler)
|
|
httpMux.HandleFunc("/debug/requests", trace.Traces)
|
|
httpMux.HandleFunc("/", statusz.StatusHandler)
|
|
|
|
if err := s.setupDebugHTTP(httpMux); err != nil {
|
|
glog.Exitf("Could not setup HTTP server: %v", err)
|
|
}
|
|
|
|
go func() {
|
|
if err := s.http.server.Serve(s.http.listen); err != nil {
|
|
glog.Exitf("Could not start HTTP server: %v", err)
|
|
}
|
|
}()
|
|
glog.Infof("Listening for HTTP on %v", s.opts.debugAddress)
|
|
|
|
select {}
|
|
}
|