package embed import ( "net" "net/url" "go.etcd.io/etcd/server/v3/embed" ) const ( DefaultHost = "localhost" DefaultPort = "0" ) // Config struct provides the configuration options for an etcd instance. type Config struct { Name string PeerURL *url.URL ClientURL *url.URL LogLevel string embed *embed.Config } // assignedAddress provides functionality to find an open host:port combination type assignedAddress struct { host, port string } // assign tries to claim a URL using the provided host and port. A connection // will be established to the assigned address to prevent other processes from // attempting to claim the host:port for 60s. // // If no host is provided, then localhost will be used as a default. // // If no port is provided, then an available port will be selected at random. func (a *assignedAddress) assign(url *url.URL) error { l, err := reserve(url.Hostname(), url.Port()) if err != nil { return err } defer l.Close() a.host, a.port, err = net.SplitHostPort(l.Addr().String()) return err } // reserve will reserve the host:port combination. If no host is provided, then // localhost is used. If no port is provided, then one is selected at random // from the pool of available ports. func reserve(host, port string) (net.Listener, error) { if host == "" { host = DefaultHost } if port == "" { port = DefaultPort } addr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort(host, port)) if err != nil { return nil, err } return net.ListenTCP("tcp", addr) } // url returns the assignedAddress as a url.URL object func (a *assignedAddress) url() url.URL { return url.URL{ Scheme: "http", Host: net.JoinHostPort(a.host, a.port), } }