github.com/emcfarlane/larking@v0.0.0-20220605172417-1704b45ee6c3/cmd/larking/main.go (about) 1 package main 2 3 import ( 4 "context" 5 "crypto/x509" 6 "flag" 7 "fmt" 8 "log" 9 "net" 10 "os" 11 12 "github.com/emcfarlane/larking" 13 "github.com/emcfarlane/larking/apipb/controlpb" 14 "github.com/emcfarlane/larking/apipb/healthpb" 15 "github.com/emcfarlane/larking/apipb/workerpb" 16 _ "github.com/emcfarlane/larking/cmd/internal/bindings" 17 "github.com/emcfarlane/larking/control" 18 "github.com/emcfarlane/larking/health" 19 "github.com/emcfarlane/larking/starlib" 20 "github.com/emcfarlane/larking/starlib/starlarkthread" 21 "github.com/emcfarlane/larking/worker" 22 "github.com/go-logr/logr" 23 "github.com/go-logr/stdr" 24 "go.starlark.net/starlark" 25 "google.golang.org/grpc" 26 "google.golang.org/grpc/credentials" 27 ) 28 29 const defaultAddr = "localhost:6060" // default webserver address 30 31 func env(key, def string) string { 32 if e := os.Getenv(key); e != "" { 33 return e 34 } 35 return def 36 } 37 38 var ( 39 flagAddr = flag.String("addr", env("LARKING_ADDRESS", defaultAddr), "Local address to listen on.") 40 flagControlAddr = flag.String("control", "https://larking.io", "Control server for credentials.") 41 flagInsecure = flag.Bool("insecure", false, "Insecure, disabled credentials.") 42 flagCreds = flag.String("credentials", env("WORKER_CREDENTIALS", ""), "Runtime variable for credentials.") 43 44 flagDir = flag.String("dir", env("LARKING_DIR", "file://./?metadata=skip"), "Set the module loading directory") 45 ) 46 47 type logStream struct { 48 grpc.ServerStream 49 log logr.Logger 50 } 51 52 func (s logStream) Context() context.Context { 53 return logr.NewContext(s.ServerStream.Context(), s.log) 54 } 55 56 func run(ctx context.Context) (err error) { 57 ctx, cancel := context.WithCancel(ctx) 58 defer cancel() 59 60 l, err := net.Listen("tcp", *flagAddr) 61 if err != nil { 62 return err 63 } 64 defer l.Close() 65 66 stdr.SetVerbosity(1) 67 log := stdr.NewWithOptions(log.New(os.Stderr, "", log.LstdFlags), stdr.Options{LogCaller: stdr.All}) 68 log = log.WithName("Larking") 69 70 unary := func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { 71 log.Info("unary request", "info", info) 72 ctx = logr.NewContext(ctx, log) 73 defer log.Info("unary end", info) 74 return handler(ctx, req) 75 } 76 77 stream := func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { 78 log.Info("stream request", "info", info) 79 defer log.Info("stream end", info) 80 return handler(srv, logStream{ 81 ServerStream: ss, 82 log: log, 83 }) 84 } 85 86 var muxOpts = []larking.MuxOption{ 87 larking.UnaryServerInterceptorOption(unary), 88 larking.StreamServerInterceptorOption(stream), 89 } 90 91 mux, err := larking.NewMux(muxOpts...) 92 if err != nil { 93 return err 94 } 95 96 healthServer := health.NewServer() 97 defer healthServer.Shutdown() 98 mux.RegisterService(&healthpb.Health_ServiceDesc, healthServer) 99 100 globals := starlib.NewGlobals() 101 loader := starlib.NewLoader(globals) 102 defer loader.Close() 103 104 var ( 105 controlClient controlpb.ControlClient = control.InsecureControlClient{} 106 name string 107 ) 108 if !*flagInsecure || *flagCreds != "" { 109 log.Info("loading worker credentials") 110 111 perRPC, err := control.OpenRPCCredentials(ctx, *flagCreds) 112 if err != nil { 113 return err 114 } 115 defer perRPC.Close() 116 117 name = perRPC.Name() 118 119 // TODO: load creds. 120 pool, err := x509.SystemCertPool() 121 if err != nil { 122 return err 123 } 124 creds := credentials.NewClientTLSFromCert(pool, "") 125 126 cc, err := grpc.DialContext( 127 ctx, *flagControlAddr, 128 grpc.WithTransportCredentials(creds), 129 grpc.WithPerRPCCredentials(perRPC), 130 ) 131 if err != nil { 132 return err 133 } 134 defer cc.Close() 135 136 controlClient = controlpb.NewControlClient(cc) 137 } 138 139 workerServer := worker.NewServer( 140 loader.Load, 141 controlClient, 142 name, 143 ) 144 mux.RegisterService(&workerpb.Worker_ServiceDesc, workerServer) 145 healthServer.SetServingStatus( 146 workerpb.Worker_ServiceDesc.ServiceName, 147 healthpb.HealthCheckResponse_SERVING, 148 ) 149 150 var svrOpts []larking.ServerOption 151 152 if *flagInsecure { 153 svrOpts = append(svrOpts, larking.InsecureServerOption()) 154 } 155 156 s, err := larking.NewServer(mux, svrOpts...) 157 if err != nil { 158 return err 159 } 160 161 // Run script 162 switch flag.NArg() { 163 case 0: 164 // nothing 165 case 1: 166 name := flag.Arg(0) 167 168 src, err := loader.LoadSource(ctx, *flagDir, name) 169 if err != nil { 170 return err 171 } 172 173 globals := starlib.NewGlobals() 174 globals["mux"] = mux // add mux! 175 thread := &starlark.Thread{ 176 Name: name, // TODO: name encoding... 177 Load: loader.Load, 178 Print: func(_ *starlark.Thread, msg string) { 179 log.Info(msg, "thread", name) 180 }, 181 } 182 starlarkthread.SetContext(thread, ctx) 183 close := starlarkthread.WithResourceStore(thread) 184 defer func() { 185 if cerr := close(); err == nil { 186 err = cerr 187 } 188 }() 189 190 module, err := starlark.ExecFile(thread, name, src, globals) 191 if err != nil { 192 return err 193 } 194 if mainFn, ok := module["main"]; ok { 195 if _, err := starlark.Call(thread, mainFn, nil, nil); err != nil { 196 return err 197 } 198 } 199 200 default: 201 return fmt.Errorf("unexpected number of args") 202 } 203 204 go func() { 205 log.Info("listening", "address", l.Addr().String()) 206 if err := s.Serve(l); err != nil { 207 log.Error(err, "server stopped") 208 } 209 cancel() 210 }() 211 <-ctx.Done() 212 return s.Shutdown(ctx) 213 } 214 215 func usage() { 216 fmt.Fprintf(os.Stderr, "usage: larking -addr="+defaultAddr+" -svc=service1 -svc=service2\n") 217 flag.PrintDefaults() 218 os.Exit(2) 219 } 220 221 func main() { 222 flag.Usage = usage 223 flag.Parse() 224 225 //if len(services) == 0 { 226 // usage() 227 //} 228 229 ctx := context.Background() 230 ctx, cancel := larking.NewOSSignalContext(ctx) 231 defer cancel() 232 233 if err := run(ctx); err != nil { 234 fmt.Println(err) 235 os.Exit(1) 236 } 237 }