Merge pull request #9399 from influxdata/js-9266-unix-socket-permissions
Allow customizing the unix socket group and permissions created by the serverpull/9687/head
commit
b24afed528
|
@ -1,6 +1,9 @@
|
|||
package httpd
|
||||
|
||||
import "github.com/influxdata/influxdb/monitor/diagnostics"
|
||||
import (
|
||||
"github.com/influxdata/influxdb/monitor/diagnostics"
|
||||
"github.com/influxdata/influxdb/toml"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultBindAddress is the default address to bind to.
|
||||
|
@ -18,39 +21,42 @@ const (
|
|||
|
||||
// Config represents a configuration for a HTTP service.
|
||||
type Config struct {
|
||||
Enabled bool `toml:"enabled"`
|
||||
BindAddress string `toml:"bind-address"`
|
||||
AuthEnabled bool `toml:"auth-enabled"`
|
||||
LogEnabled bool `toml:"log-enabled"`
|
||||
WriteTracing bool `toml:"write-tracing"`
|
||||
PprofEnabled bool `toml:"pprof-enabled"`
|
||||
HTTPSEnabled bool `toml:"https-enabled"`
|
||||
HTTPSCertificate string `toml:"https-certificate"`
|
||||
HTTPSPrivateKey string `toml:"https-private-key"`
|
||||
MaxRowLimit int `toml:"max-row-limit"`
|
||||
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"`
|
||||
MaxBodySize int `toml:"max-body-size"`
|
||||
AccessLogPath string `toml:"access-log-path"`
|
||||
Enabled bool `toml:"enabled"`
|
||||
BindAddress string `toml:"bind-address"`
|
||||
AuthEnabled bool `toml:"auth-enabled"`
|
||||
LogEnabled bool `toml:"log-enabled"`
|
||||
WriteTracing bool `toml:"write-tracing"`
|
||||
PprofEnabled bool `toml:"pprof-enabled"`
|
||||
HTTPSEnabled bool `toml:"https-enabled"`
|
||||
HTTPSCertificate string `toml:"https-certificate"`
|
||||
HTTPSPrivateKey string `toml:"https-private-key"`
|
||||
MaxRowLimit int `toml:"max-row-limit"`
|
||||
MaxConnectionLimit int `toml:"max-connection-limit"`
|
||||
SharedSecret string `toml:"shared-secret"`
|
||||
Realm string `toml:"realm"`
|
||||
UnixSocketEnabled bool `toml:"unix-socket-enabled"`
|
||||
UnixSocketGroup *toml.Group `toml:"unix-socket-group"`
|
||||
UnixSocketPermissions toml.FileMode `toml:"unix-socket-permissions"`
|
||||
BindSocket string `toml:"bind-socket"`
|
||||
MaxBodySize int `toml:"max-body-size"`
|
||||
AccessLogPath string `toml:"access-log-path"`
|
||||
}
|
||||
|
||||
// NewConfig returns a new Config with default settings.
|
||||
func NewConfig() Config {
|
||||
return Config{
|
||||
Enabled: true,
|
||||
BindAddress: DefaultBindAddress,
|
||||
LogEnabled: true,
|
||||
PprofEnabled: true,
|
||||
HTTPSEnabled: false,
|
||||
HTTPSCertificate: "/etc/ssl/influxdb.pem",
|
||||
MaxRowLimit: 0,
|
||||
Realm: DefaultRealm,
|
||||
UnixSocketEnabled: false,
|
||||
BindSocket: DefaultBindSocket,
|
||||
MaxBodySize: DefaultMaxBodySize,
|
||||
Enabled: true,
|
||||
BindAddress: DefaultBindAddress,
|
||||
LogEnabled: true,
|
||||
PprofEnabled: true,
|
||||
HTTPSEnabled: false,
|
||||
HTTPSCertificate: "/etc/ssl/influxdb.pem",
|
||||
MaxRowLimit: 0,
|
||||
Realm: DefaultRealm,
|
||||
UnixSocketEnabled: false,
|
||||
UnixSocketPermissions: 0777,
|
||||
BindSocket: DefaultBindSocket,
|
||||
MaxBodySize: DefaultMaxBodySize,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -55,6 +55,8 @@ type Service struct {
|
|||
err chan error
|
||||
|
||||
unixSocket bool
|
||||
unixSocketPerm uint32
|
||||
unixSocketGroup int
|
||||
bindSocket string
|
||||
unixSocketListener net.Listener
|
||||
|
||||
|
@ -66,20 +68,24 @@ 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),
|
||||
unixSocket: c.UnixSocketEnabled,
|
||||
bindSocket: c.BindSocket,
|
||||
Handler: NewHandler(c),
|
||||
Logger: zap.NewNop(),
|
||||
addr: c.BindAddress,
|
||||
https: c.HTTPSEnabled,
|
||||
cert: c.HTTPSCertificate,
|
||||
key: c.HTTPSPrivateKey,
|
||||
limit: c.MaxConnectionLimit,
|
||||
err: make(chan error),
|
||||
unixSocket: c.UnixSocketEnabled,
|
||||
unixSocketPerm: uint32(c.UnixSocketPermissions),
|
||||
bindSocket: c.BindSocket,
|
||||
Handler: NewHandler(c),
|
||||
Logger: zap.NewNop(),
|
||||
}
|
||||
if s.key == "" {
|
||||
s.key = s.cert
|
||||
}
|
||||
if c.UnixSocketGroup != nil {
|
||||
s.unixSocketGroup = int(*c.UnixSocketGroup)
|
||||
}
|
||||
s.Handler.Logger = s.Logger
|
||||
return s
|
||||
}
|
||||
|
@ -133,6 +139,16 @@ func (s *Service) Open() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if s.unixSocketPerm != 0 {
|
||||
if err := os.Chmod(s.bindSocket, os.FileMode(s.unixSocketPerm)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if s.unixSocketGroup != 0 {
|
||||
if err := os.Chown(s.bindSocket, -1, s.unixSocketGroup); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
s.Logger.Info("Listening on unix socket",
|
||||
zap.Stringer("addr", listener.Addr()))
|
||||
|
|
49
toml/toml.go
49
toml/toml.go
|
@ -3,9 +3,11 @@ package toml // import "github.com/influxdata/influxdb/toml"
|
|||
|
||||
import (
|
||||
"encoding"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"os/user"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -94,6 +96,53 @@ func (s *Size) UnmarshalText(text []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
type FileMode uint32
|
||||
|
||||
func (m *FileMode) UnmarshalText(text []byte) error {
|
||||
// Ignore if there is no value set.
|
||||
if len(text) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
mode, err := strconv.ParseUint(string(text), 8, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if mode == 0 {
|
||||
return errors.New("file mode cannot be zero")
|
||||
}
|
||||
*m = FileMode(mode)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m FileMode) MarshalText() (text []byte, err error) {
|
||||
if m != 0 {
|
||||
return []byte(fmt.Sprintf("%04o", m)), nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type Group int
|
||||
|
||||
func (g *Group) UnmarshalTOML(data interface{}) error {
|
||||
if grpName, ok := data.(string); ok {
|
||||
group, err := user.LookupGroup(grpName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
gid, err := strconv.Atoi(group.Gid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*g = Group(gid)
|
||||
return nil
|
||||
} else if gid, ok := data.(int64); ok {
|
||||
*g = Group(gid)
|
||||
return nil
|
||||
}
|
||||
return errors.New("group must be a name (string) or id (int)")
|
||||
}
|
||||
|
||||
func ApplyEnvOverrides(getenv func(string) string, prefix string, val interface{}) error {
|
||||
if getenv == nil {
|
||||
getenv = os.Getenv
|
||||
|
|
|
@ -4,6 +4,9 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"math"
|
||||
"os/user"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -62,6 +65,81 @@ func TestSize_UnmarshalText(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestFileMode_MarshalText(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
mode int
|
||||
want string
|
||||
}{
|
||||
{mode: 0755, want: `0755`},
|
||||
{mode: 0777, want: `0777`},
|
||||
{mode: 01777, want: `1777`},
|
||||
} {
|
||||
mode := itoml.FileMode(test.mode)
|
||||
if got, err := mode.MarshalText(); err != nil {
|
||||
t.Errorf("unexpected error: %s", err)
|
||||
} else if test.want != string(got) {
|
||||
t.Errorf("wanted: %v got: %v", test.want, string(got))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileMode_UnmarshalText(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
str string
|
||||
want uint32
|
||||
}{
|
||||
{str: ``, want: 0},
|
||||
{str: `0777`, want: 0777},
|
||||
{str: `777`, want: 0777},
|
||||
{str: `1777`, want: 01777},
|
||||
{str: `0755`, want: 0755},
|
||||
} {
|
||||
var mode itoml.FileMode
|
||||
if err := mode.UnmarshalText([]byte(test.str)); err != nil {
|
||||
t.Errorf("unexpected error: %s", err)
|
||||
} else if mode != itoml.FileMode(test.want) {
|
||||
t.Errorf("wanted: %04o got: %04o", test.want, mode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGroup_UnmarshalTOML(t *testing.T) {
|
||||
// Skip this test on windows since it does not support setting the group anyway.
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("unsupported on windows")
|
||||
}
|
||||
|
||||
// Find the current user ID so we can use that group name.
|
||||
u, err := user.Current()
|
||||
if err != nil {
|
||||
t.Skipf("unable to find the current user: %s", err)
|
||||
}
|
||||
|
||||
// Lookup the group by the group id.
|
||||
gr, err := user.LookupGroupId(u.Gid)
|
||||
if err == nil {
|
||||
var group itoml.Group
|
||||
if err := group.UnmarshalTOML(gr.Name); err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
} else if got, want := u.Gid, strconv.Itoa(int(group)); got != want {
|
||||
t.Fatalf("unexpected group id: %s != %s", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to convert the group to an integer so we can test reading an integer.
|
||||
gid, err := strconv.Atoi(u.Gid)
|
||||
if err != nil {
|
||||
t.Fatalf("group id is not an integer: %s", err)
|
||||
}
|
||||
|
||||
var group itoml.Group
|
||||
if err := group.UnmarshalTOML(int64(gid)); err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
} else if int(group) != gid {
|
||||
t.Fatalf("unexpected group id: %d != %d", gid, int(group))
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfig_Encode(t *testing.T) {
|
||||
var c run.Config
|
||||
c.Coordinator.WriteTimeout = itoml.Duration(time.Minute)
|
||||
|
|
Loading…
Reference in New Issue