add support for unix socket binding service

pull/7135/head
kun 2016-08-10 12:25:59 +08:00 committed by oiooj
parent e8104e2d81
commit 6945655be2
5 changed files with 85 additions and 19 deletions

View File

@ -3,6 +3,7 @@
### Features
- [#7120](https://github.com/influxdata/influxdb/issues/7120): Add additional statistics to query executor.
- [#7135](https://github.com/influxdata/influxdb/pull/7135): Support enable HTTP service over unix domain socket. Thanks @oiooj
### Bugfixes

View File

@ -173,6 +173,9 @@ reporting-disabled = false
max-row-limit = 10000
realm = "InfluxDB"
unix-socket-enabled = false # enable http service over unix domain socket
# bind-socket = "/var/run/influxdb.sock"
###
### [subsciber]
###

View File

@ -6,6 +6,9 @@ const (
// DefaultRealm is the default realm sent back when issuing a basic auth challenge.
DefaultRealm = "InfluxDB"
// DefaultBindSocket is the default unix socket to bind to.
DefaultBindSocket = "/var/run/influxdb.sock"
)
// Config represents a configuration for a HTTP service.
@ -22,17 +25,21 @@ type Config struct {
MaxConnectionLimit int `toml:"max-connection-limit"`
SharedSecret string `toml:"shared-secret"`
Realm string `toml:"realm"`
UnixSocketEnabled bool `toml:"unix-socket-enabled"`
BindSocket string `toml:"bind-socket"`
}
// NewConfig returns a new Config with default settings.
func NewConfig() Config {
return Config{
Enabled: true,
BindAddress: DefaultBindAddress,
LogEnabled: true,
HTTPSEnabled: false,
HTTPSCertificate: "/etc/ssl/influxdb.pem",
MaxRowLimit: DefaultChunkSize,
Realm: DefaultRealm,
Enabled: true,
BindAddress: DefaultBindAddress,
LogEnabled: true,
HTTPSEnabled: false,
HTTPSCertificate: "/etc/ssl/influxdb.pem",
MaxRowLimit: DefaultChunkSize,
Realm: DefaultRealm,
UnixSocketEnabled: false,
BindSocket: DefaultBindSocket,
}
}

View File

@ -18,6 +18,8 @@ log-enabled = true
write-tracing = true
https-enabled = true
https-certificate = "/dev/null"
unix-socket-enabled = true
bind-socket = "/var/run/influxdb.sock"
`, &c); err != nil {
t.Fatal(err)
}
@ -37,6 +39,10 @@ https-certificate = "/dev/null"
t.Fatalf("unexpected https enabled: %v", c.HTTPSEnabled)
} else if c.HTTPSCertificate != "/dev/null" {
t.Fatalf("unexpected https certificate: %v", c.HTTPSCertificate)
} else if c.UnixSocketEnabled != true {
t.Fatalf("unexpected unix socket enabled: %v", c.UnixSocketEnabled)
} else if c.BindSocket != "/var/run/influxdb.sock" {
t.Fatalf("unexpected bind unix socket: %v", c.BindSocket)
}
}

View File

@ -8,7 +8,10 @@ import (
"net"
"net/http"
"os"
"path"
"runtime"
"strings"
"syscall"
"time"
"github.com/influxdata/influxdb/models"
@ -46,6 +49,10 @@ type Service struct {
limit int
err chan error
unixSocket bool
bindSocket string
unixSocketListener net.Listener
Handler *Handler
Logger *log.Logger
@ -54,14 +61,16 @@ type Service struct {
// NewService returns a new instance of Service.
func NewService(c Config) *Service {
s := &Service{
addr: c.BindAddress,
https: c.HTTPSEnabled,
cert: c.HTTPSCertificate,
key: c.HTTPSPrivateKey,
limit: c.MaxConnectionLimit,
err: make(chan error),
Handler: NewHandler(c),
Logger: log.New(os.Stderr, "[httpd] ", log.LstdFlags),
addr: c.BindAddress,
https: c.HTTPSEnabled,
cert: c.HTTPSCertificate,
key: c.HTTPSPrivateKey,
limit: c.MaxConnectionLimit,
err: make(chan error),
unixSocket: c.UnixSocketEnabled,
bindSocket: c.BindSocket,
Handler: NewHandler(c),
Logger: log.New(os.Stderr, "[httpd] ", log.LstdFlags),
}
if s.key == "" {
s.key = s.cert
@ -101,6 +110,29 @@ func (s *Service) Open() error {
s.ln = listener
}
// Open unix socket listener.
if s.unixSocket {
if runtime.GOOS == "windows" {
return fmt.Errorf("unable to use unix socket on windows")
}
if err := os.MkdirAll(path.Dir(s.bindSocket), 0777); err != nil {
return err
}
if err := syscall.Unlink(s.bindSocket); err != nil && !os.IsNotExist(err) {
return err
}
listener, err := net.Listen("unix", s.bindSocket)
if err != nil {
return err
}
s.Logger.Println("Listening on unix socket:", listener.Addr().String())
s.unixSocketListener = listener
go s.serveUnixSocket()
}
// Enforce a connection limit if one has been given.
if s.limit > 0 {
s.ln = LimitListener(s.ln, s.limit)
@ -120,14 +152,21 @@ func (s *Service) Open() error {
}
// Begin listening for requests in a separate goroutine.
go s.serve()
go s.serveTCP()
return nil
}
// Close closes the underlying listener.
func (s *Service) Close() error {
if s.ln != nil {
return s.ln.Close()
if err := s.ln.Close(); err != nil {
return err
}
}
if s.unixSocketListener != nil {
if err := s.unixSocketListener.Close(); err != nil {
return err
}
}
return nil
}
@ -156,11 +195,21 @@ func (s *Service) Statistics(tags map[string]string) []models.Statistic {
return s.Handler.Statistics(models.Tags{"bind": s.addr}.Merge(tags))
}
// serveTCP serves the handler from the TCP listener.
func (s *Service) serveTCP() {
s.serve(s.ln)
}
// serveUnixSocket serves the handler from the unix socket listener.
func (s *Service) serveUnixSocket() {
s.serve(s.unixSocketListener)
}
// serve serves the handler from the listener.
func (s *Service) serve() {
func (s *Service) serve(listener net.Listener) {
// The listener was closed so exit
// See https://github.com/golang/go/issues/4373
err := http.Serve(s.ln, s.Handler)
err := http.Serve(listener, s.Handler)
if err != nil && !strings.Contains(err.Error(), "closed") {
s.err <- fmt.Errorf("listener failed: addr=%s, err=%s", s.Addr(), err)
}