blob: b3b80bfadedaa5b1a6a3395723d3e5007b4450d2 [file] [log] [blame]
package server
import (
"context"
"flag"
"net"
"net/http"
"github.com/improbable-eng/grpc-web/go/grpcweb"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/reflection"
"google.golang.org/grpc/status"
"k8s.io/klog/v2"
apb "source.monogon.dev/cloud/api"
"source.monogon.dev/cloud/lib/component"
)
// Config is the main configuration of the apigw server. It's usually populated
// from flags via RegisterFlags, but can also be set manually (eg. in tests).
type Config struct {
component.Configuration
PublicListenAddress string
}
// RegisterFlags registers the component configuration to be provided by flags.
// This must be called exactly once before then calling flags.Parse().
func (c *Config) RegisterFlags() {
c.Configuration.RegisterFlags("apigw")
flag.StringVar(&c.PublicListenAddress, "apigw_public_grpc_listen_address", ":8080", "Address to listen at for public/user gRPC connections for apigw")
}
// Server runs the apigw server. It listens on two interfaces:
// - Internal gRPC, which is authenticated using TLS and authorized by CA. This
// is to be used for internal RPCs, eg. management/debug.
// - Public gRPC-Web, which is currently unauthenticated.
type Server struct {
Config Config
// ListenGRPC will contain the address at which the internal gRPC server is
// listening after .Start() has been called. This can differ from the configured
// value if the configuration requests any port (via :0).
ListenGRPC string
// ListenPublic will contain the address at which the public API server is
// listening after .Start() has been called. This can differ from the configured
// value if the configuration requests any port (via :0).
ListenPublic string
}
func (s *Server) startInternalGRPC(ctx context.Context) {
g := grpc.NewServer(s.Config.GRPCServerOptions()...)
lis, err := net.Listen("tcp", s.Config.GRPCListenAddress)
if err != nil {
klog.Exitf("Could not listen: %v", err)
}
s.ListenGRPC = lis.Addr().String()
reflection.Register(g)
klog.Infof("Internal gRPC listening on %s", s.ListenGRPC)
go func() {
err := g.Serve(lis)
if err != ctx.Err() {
klog.Exitf("Internal gRPC serve failed: %v", err)
}
}()
}
func (s *Server) startPublic(ctx context.Context) {
g := grpc.NewServer(grpc.Creds(insecure.NewCredentials()))
lis, err := net.Listen("tcp", s.Config.PublicListenAddress)
if err != nil {
klog.Exitf("Could not listen: %v", err)
}
s.ListenPublic = lis.Addr().String()
reflection.Register(g)
apb.RegisterIAMServer(g, s)
wrapped := grpcweb.WrapServer(g)
server := http.Server{
Addr: s.Config.PublicListenAddress,
Handler: http.HandlerFunc(wrapped.ServeHTTP),
}
klog.Infof("Public API listening on %s", s.ListenPublic)
go func() {
err := server.Serve(lis)
if err != ctx.Err() {
klog.Exitf("Public API serve failed: %v", err)
}
}()
}
// Start runs the two listeners of the server. The process will fail (via
// klog.Exit) if any of the listeners/servers fail to start.
func (s *Server) Start(ctx context.Context) {
s.startInternalGRPC(ctx)
s.startPublic(ctx)
}
func (s *Server) WhoAmI(ctx context.Context, req *apb.WhoAmIRequest) (*apb.WhoAmIResponse, error) {
klog.Infof("req: %+v", req)
return nil, status.Error(codes.Unimplemented, "unimplemented")
}