commit 1397e10225d8c6fd079a86fccd58fb5d0f4200bc Author: Florian Klink Date: Fri Mar 29 10:06:34 2024 +0100 feat(bigtable/emulator): allow listening on Unix Domain Sockets cbtemulator listening on unix domain sockets is much easier than trying to allocate free TCP ports, especially if many cbtemulators are run at the same time in integration tests. This adds an additional flag, address, which has priority if it's set, rather than host:port. `NewServer` already takes a `laddr string`, so we simply check for it to contain slashes, and if so, listen on unix, rather than TCP. diff --git a/bigtable/bttest/inmem.go b/bigtable/bttest/inmem.go index 556abc2a85..33e4bf2667 100644 --- a/bttest/inmem.go +++ b/bttest/inmem.go @@ -40,6 +40,7 @@ import ( "math" "math/rand" "net" + "os" "regexp" "sort" "strings" @@ -106,7 +107,15 @@ type server struct { // The Server will be listening for gRPC connections, without TLS, // on the provided address. The resolved address is named by the Addr field. func NewServer(laddr string, opt ...grpc.ServerOption) (*Server, error) { - l, err := net.Listen("tcp", laddr) + var l net.Listener + var err error + + // If the address contains slashes, listen on a unix domain socket instead. + if strings.Contains(laddr, "/") { + l, err = net.Listen("unix", laddr) + } else { + l, err = net.Listen("tcp", laddr) + } if err != nil { return nil, err } diff --git a/bigtable/cmd/emulator/cbtemulator.go b/bigtable/cmd/emulator/cbtemulator.go index 144c09ffb1..deaf69b717 100644 --- a/cmd/emulator/cbtemulator.go +++ b/cmd/emulator/cbtemulator.go @@ -27,8 +27,9 @@ import ( ) var ( - host = flag.String("host", "localhost", "the address to bind to on the local machine") - port = flag.Int("port", 9000, "the port number to bind to on the local machine") + host = flag.String("host", "localhost", "the address to bind to on the local machine") + port = flag.Int("port", 9000, "the port number to bind to on the local machine") + address = flag.String("address", "", "address:port number or unix socket path to listen on. Has priority over host/port") ) const ( @@ -42,7 +43,15 @@ func main() { grpc.MaxRecvMsgSize(maxMsgSize), grpc.MaxSendMsgSize(maxMsgSize), } - srv, err := bttest.NewServer(fmt.Sprintf("%s:%d", *host, *port), opts...) + + var laddr string + if *address != "" { + laddr = *address + } else { + laddr = fmt.Sprintf("%s:%d", *host, *port) + } + + srv, err := bttest.NewServer(laddr, opts...) if err != nil { log.Fatalf("failed to start emulator: %v", err) } commit ce16f843d6c93159d86b3807c6d9ff66e43aac67 Author: Florian Klink Date: Fri Mar 29 11:53:15 2024 +0100 feat(bigtable): clean up unix socket on close Call srv.Close when receiving an interrupt, and delete the unix domain socket in that function. diff --git a/bigtable/bttest/inmem.go b/bigtable/bttest/inmem.go index 33e4bf2667..0dc96024b1 100644 --- a/bttest/inmem.go +++ b/bttest/inmem.go @@ -148,6 +148,11 @@ func (s *Server) Close() { s.srv.Stop() s.l.Close() + + // clean up unix socket + if strings.Contains(s.Addr, "/") { + _ = os.Remove(s.Addr) + } } func (s *server) CreateTable(ctx context.Context, req *btapb.CreateTableRequest) (*btapb.Table, error) { diff --git a/bigtable/cmd/emulator/cbtemulator.go b/bigtable/cmd/emulator/cbtemulator.go index deaf69b717..5a9e8f7a8c 100644 --- a/cmd/emulator/cbtemulator.go +++ b/cmd/emulator/cbtemulator.go @@ -18,9 +18,12 @@ cbtemulator launches the in-memory Cloud Bigtable server on the given address. package main import ( + "context" "flag" "fmt" "log" + "os" + "os/signal" "cloud.google.com/go/bigtable/bttest" "google.golang.org/grpc" @@ -51,11 +54,18 @@ func main() { laddr = fmt.Sprintf("%s:%d", *host, *port) } + ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt) + defer stop() + srv, err := bttest.NewServer(laddr, opts...) if err != nil { log.Fatalf("failed to start emulator: %v", err) } fmt.Printf("Cloud Bigtable emulator running on %s\n", srv.Addr) - select {} + select { + case <-ctx.Done(): + srv.Close() + stop() + } }