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