blob: 97fb3930168741baa78b2a83bdc46cf62e10512f [file] [log] [blame]
Serge Bazanski4abeb132022-10-11 11:32:19 +02001package server
2
3import (
4 "context"
5 "flag"
6 "fmt"
7 "net"
8 "os"
9
10 "google.golang.org/grpc"
11 "google.golang.org/grpc/reflection"
12 "k8s.io/klog/v2"
13
14 "source.monogon.dev/cloud/bmaas/bmdb"
15 apb "source.monogon.dev/cloud/bmaas/server/api"
16 "source.monogon.dev/cloud/lib/component"
17)
18
19type Config struct {
20 Component component.ComponentConfig
21 BMDB bmdb.BMDB
22
23 // PublicListenAddress is the address at which the 'public' (agent-facing) gRPC
24 // server listener will run.
25 PublicListenAddress string
26}
27
28// TODO(q3k): factor this out to BMDB library?
29func runtimeInfo() string {
30 hostname, _ := os.Hostname()
31 if hostname == "" {
32 hostname = "UNKNOWN"
33 }
34 return fmt.Sprintf("host %s", hostname)
35}
36
37func (c *Config) RegisterFlags() {
38 c.Component.RegisterFlags("srv")
39 c.BMDB.ComponentName = "srv"
40 c.BMDB.RuntimeInfo = runtimeInfo()
41 c.BMDB.Database.RegisterFlags("bmdb")
42
43 flag.StringVar(&c.PublicListenAddress, "srv_public_grpc_listen_address", ":8080", "Address to listen at for public/user gRPC connections for bmdbsrv")
44}
45
46type Server struct {
47 Config Config
48
49 // ListenGRPC will contain the address at which the internal gRPC server is
50 // listening after .Start() has been called. This can differ from the configured
51 // value if the configuration requests any port (via :0).
52 ListenGRPC string
53 // ListenPublic will contain the address at which the 'public' (agent-facing)
54 // gRPC server is lsitening after .Start() has been called.
55 ListenPublic string
56
57 bmdb *bmdb.Connection
58 acsvc *agentCallbackService
59}
60
61func (s *Server) startPublic(ctx context.Context) {
62 g := grpc.NewServer(s.Config.Component.GRPCServerOptionsPublic()...)
63 lis, err := net.Listen("tcp", s.Config.PublicListenAddress)
64 if err != nil {
65 klog.Exitf("Could not listen: %v", err)
66 }
67 s.ListenPublic = lis.Addr().String()
68 apb.RegisterAgentCallbackServer(g, s.acsvc)
69 reflection.Register(g)
70
71 klog.Infof("Public API listening on %s", s.ListenPublic)
72 go func() {
73 err := g.Serve(lis)
74 if err != ctx.Err() {
75 klog.Exitf("Public gRPC serve failed: %v", err)
76 }
77 }()
78}
79
80func (s *Server) startInternalGRPC(ctx context.Context) {
81 g := grpc.NewServer(s.Config.Component.GRPCServerOptions()...)
82 lis, err := net.Listen("tcp", s.Config.Component.GRPCListenAddress)
83 if err != nil {
84 klog.Exitf("Could not listen: %v", err)
85 }
86 s.ListenGRPC = lis.Addr().String()
87
88 reflection.Register(g)
89 klog.Infof("Internal gRPC listening on %s", s.ListenGRPC)
90 go func() {
91 err := g.Serve(lis)
92 if err != ctx.Err() {
93 klog.Exitf("Internal gRPC serve failed: %v", err)
94 }
95 }()
96}
97
98// Start the BMaaS Server in background goroutines. This should only be called
99// once. The process will exit with debug logs if starting the server failed.
100func (s *Server) Start(ctx context.Context) {
101 conn, err := s.Config.BMDB.Open(true)
102 if err != nil {
103 klog.Exitf("Failed to connect to BMDB: %v", err)
104 }
105 s.acsvc = &agentCallbackService{
106 s: s,
107 }
108 s.bmdb = conn
109 s.startInternalGRPC(ctx)
110 s.startPublic(ctx)
111}