Skip to content

Commit

Permalink
Allow multiple endpoints where server is exposed at
Browse files Browse the repository at this point in the history
  • Loading branch information
michalpristas committed Nov 11, 2021
1 parent 71428f9 commit 12c7d5d
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 63 deletions.
118 changes: 60 additions & 58 deletions cmd/fleet/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,84 +40,86 @@ func diagConn(c net.Conn, s http.ConnState) {
}

func runServer(ctx context.Context, router *httprouter.Router, cfg *config.Server) error {
listeners := cfg.BindEndpoints()

addr := cfg.BindAddress()
rdto := cfg.Timeouts.Read
wrto := cfg.Timeouts.Write
idle := cfg.Timeouts.Idle
rdhr := cfg.Timeouts.ReadHeader
mhbz := cfg.Limits.MaxHeaderByteSize
bctx := func(net.Listener) context.Context { return ctx }

log.Info().
Str("bind", addr).
Dur("rdTimeout", rdto).
Dur("wrTimeout", wrto).
Msg("server listening")

server := http.Server{
Addr: addr,
ReadTimeout: rdto,
WriteTimeout: wrto,
IdleTimeout: idle,
ReadHeaderTimeout: rdhr,
Handler: router,
BaseContext: bctx,
ConnState: diagConn,
MaxHeaderBytes: mhbz,
ErrorLog: errLogger(),
}

forceCh := make(chan struct{})
defer close(forceCh)

// handler to close server
go func() {
select {
case <-ctx.Done():
log.Debug().Msg("force server close on ctx.Done()")
server.Close()
case <-forceCh:
log.Debug().Msg("go routine forced closed on exit")
for _, addr := range listeners {
log.Info().
Str("bind", addr).
Dur("rdTimeout", rdto).
Dur("wrTimeout", wrto).
Msg("server listening")

server := http.Server{
Addr: addr,
ReadTimeout: rdto,
WriteTimeout: wrto,
IdleTimeout: idle,
ReadHeaderTimeout: rdhr,
Handler: router,
BaseContext: bctx,
ConnState: diagConn,
MaxHeaderBytes: mhbz,
ErrorLog: errLogger(),
}
}()

var listenCfg net.ListenConfig
forceCh := make(chan struct{})
defer close(forceCh)

ln, err := listenCfg.Listen(ctx, "tcp", addr)
if err != nil {
return err
}
// handler to close server
go func() {
select {
case <-ctx.Done():
log.Debug().Msg("force server close on ctx.Done()")
server.Close()
case <-forceCh:
log.Debug().Msg("go routine forced closed on exit")
}
}()

// Bind the deferred Close() to the stack variable to handle case where 'ln' is wrapped
defer func() { ln.Close() }()
var listenCfg net.ListenConfig

// Conn Limiter must be before the TLS handshake in the stack;
// The server should not eat the cost of the handshake if there
// is no capacity to service the connection.
// Also, it appears the HTTP2 implementation depends on the tls.Listener
// being at the top of the stack.
ln = wrapConnLimitter(ctx, ln, cfg)

if cfg.TLS != nil && cfg.TLS.IsEnabled() {
commonTlsCfg, err := tlscommon.LoadTLSServerConfig(cfg.TLS)
ln, err := listenCfg.Listen(ctx, "tcp", addr)
if err != nil {
return err
}
server.TLSConfig = commonTlsCfg.ToConfig()

// Must enable http/2 in the configuration explicitly.
// (see https://golang.org/pkg/net/http/#Server.Serve)
server.TLSConfig.NextProtos = []string{"h2", "http/1.1"}
// Bind the deferred Close() to the stack variable to handle case where 'ln' is wrapped
defer func() { ln.Close() }()

ln = tls.NewListener(ln, server.TLSConfig)
// Conn Limiter must be before the TLS handshake in the stack;
// The server should not eat the cost of the handshake if there
// is no capacity to service the connection.
// Also, it appears the HTTP2 implementation depends on the tls.Listener
// being at the top of the stack.
ln = wrapConnLimitter(ctx, ln, cfg)

} else {
log.Warn().Msg("exposed over insecure HTTP; enablement of TLS is strongly recommended")
}
if cfg.TLS != nil && cfg.TLS.IsEnabled() {
commonTlsCfg, err := tlscommon.LoadTLSServerConfig(cfg.TLS)
if err != nil {
return err
}
server.TLSConfig = commonTlsCfg.ToConfig()

if err := server.Serve(ln); err != nil && err != http.ErrServerClosed {
return err
// Must enable http/2 in the configuration explicitly.
// (see https://golang.org/pkg/net/http/#Server.Serve)
server.TLSConfig.NextProtos = []string{"h2", "http/1.1"}

ln = tls.NewListener(ln, server.TLSConfig)

} else {
log.Warn().Msg("exposed over insecure HTTP; enablement of TLS is strongly recommended")
}

if err := server.Serve(ln); err != nil && err != http.ErrServerClosed {
return err
}
}

return nil
Expand Down
38 changes: 34 additions & 4 deletions internal/pkg/config/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,16 @@ func (c *ServerBulk) InitDefaults() {
c.FlushMaxPending = 8
}

type Endpoint struct {
Host string `config:"host"`
Port uint16 `config:"port"`
}

// Server is the configuration for the server
type Server struct {
Host string `config:"host"`
Port uint16 `config:"port"`
Host string `config:"host"` // TODO: deprecated use Endpoints
Port uint16 `config:"port"` // TODO: deprecated use Endpoints
Endpoints []Endpoint `config:"endpoints"`
TLS *tlscommon.ServerConfig `config:"ssl"`
Timeouts ServerTimeouts `config:"timeouts"`
Profiler ServerProfiler `config:"profiler"`
Expand All @@ -80,13 +86,37 @@ func (c *Server) InitDefaults() {
c.Bulk.InitDefaults()
}

// BindEndpoints returns the binding address for the all HTTP server listeners.
func (c *Server) BindEndpoints() []string {
endpoints := map[string]bool{
c.BindAddress(): true,
}

// add each of the endpoints to collection,
for _, ep := range c.Endpoints {
e := bindAddress(ep.Host, ep.Port)
endpoints[e] = true
}

// we need to get rid of duplicates so we dont have port collision
uniqueEndpoints := make([]string, 0, len(endpoints))
for ep := range endpoints {
uniqueEndpoints = append(uniqueEndpoints, ep)
}

return uniqueEndpoints
}

// BindAddress returns the binding address for the HTTP server.
func (c *Server) BindAddress() string {
host := c.Host
return bindAddress(c.Host, c.Port)
}

func bindAddress(host string, port uint16) string {
if strings.Count(host, ":") > 1 && strings.Count(host, "]") == 0 {
host = "[" + host + "]"
}
return fmt.Sprintf("%s:%d", host, c.Port)
return fmt.Sprintf("%s:%d", host, port)
}

// Input is the input defined by Agent to run Fleet Server.
Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
"github.com/elastic/fleet-server/v7/internal/pkg/build"
)

const defaultVersion = "8.1.0"
const defaultVersion = "7.16.0"

var (
Version string = defaultVersion
Expand Down

0 comments on commit 12c7d5d

Please sign in to comment.