Skip to content

Commit

Permalink
Merge pull request #7135 from oiooj/unixsocket-feature
Browse files Browse the repository at this point in the history
enable HTTP service over unix domain socket
  • Loading branch information
jsternberg authored Aug 10, 2016
2 parents e8104e2 + 6945655 commit 870cea0
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 19 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
3 changes: 3 additions & 0 deletions etc/config.sample.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
###
Expand Down
21 changes: 14 additions & 7 deletions services/httpd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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,
}
}
6 changes: 6 additions & 0 deletions services/httpd/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand All @@ -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)
}
}

Expand Down
73 changes: 61 additions & 12 deletions services/httpd/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import (
"net"
"net/http"
"os"
"path"
"runtime"
"strings"
"syscall"
"time"

"github.com/influxdata/influxdb/models"
Expand Down Expand Up @@ -46,6 +49,10 @@ type Service struct {
limit int
err chan error

unixSocket bool
bindSocket string
unixSocketListener net.Listener

Handler *Handler

Logger *log.Logger
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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
}
Expand Down Expand Up @@ -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)
}
Expand Down

0 comments on commit 870cea0

Please sign in to comment.