diff --git a/flags.go b/flags.go new file mode 100644 index 0000000..8ba7f1a --- /dev/null +++ b/flags.go @@ -0,0 +1,52 @@ +package main + +import ( + "fmt" + "strings" + + "github.com/haproxytech/haproxy-consul-connect/haproxy" +) + +type stringSliceFlag []string + +func (i *stringSliceFlag) String() string { + return "" +} + +func (i *stringSliceFlag) Set(value string) error { + *i = append(*i, value) + return nil +} + +func makeHAProxyParams(flags stringSliceFlag) (haproxy.HAProxyParams, error) { + params := haproxy.HAProxyParams{ + Defaults: map[string]string{}, + Globals: map[string]string{}, + } + + for _, flag := range flags { + parts := strings.Split(flag, "=") + if len(parts) != 2 { + return params, fmt.Errorf("bad haproxy-param flag %s, expected {type}.{name}={value}", flag) + } + + dot := strings.IndexByte(parts[0], '.') + if dot == -1 { + return params, fmt.Errorf("bad haproxy-param flag %s, expected {type}.{name}={value}", flag) + } + + var t map[string]string + switch parts[0][:dot] { + case "defaults": + t = params.Defaults + case "global": + t = params.Globals + default: + return params, fmt.Errorf("bad haproxy-param flag %s, param type must be `defaults` or `global`", flag) + } + + t[parts[0][dot+1:]] = parts[1] + } + + return params, nil +} diff --git a/flags_test.go b/flags_test.go new file mode 100644 index 0000000..fa6371e --- /dev/null +++ b/flags_test.go @@ -0,0 +1,31 @@ +package main + +import ( + "testing" + + "github.com/haproxytech/haproxy-consul-connect/haproxy" + "github.com/stretchr/testify/require" +) + +func TestMakeHAProxyParams(t *testing.T) { + flags := stringSliceFlag{ + "defaults.test.with.dots=3", + "defaults.another=abdc", + "global.with.spaces=hey I have spaces", + "global.with.dots=hey.I.have.dots", + } + + r, err := makeHAProxyParams(flags) + require.NoError(t, err) + + require.Equal(t, haproxy.HAProxyParams{ + Defaults: map[string]string{ + "test.with.dots": "3", + "another": "abdc", + }, + Globals: map[string]string{ + "with.spaces": "hey I have spaces", + "with.dots": "hey.I.have.dots", + }, + }, r) +} diff --git a/haproxy/config.go b/haproxy/config.go index f62b8d2..988a2a3 100644 --- a/haproxy/config.go +++ b/haproxy/config.go @@ -3,6 +3,7 @@ package haproxy import ( "crypto/rand" "encoding/base64" + "fmt" "io/ioutil" "os" "path" @@ -14,18 +15,32 @@ import ( log "github.com/sirupsen/logrus" ) +var defaultsHAProxyParams = HAProxyParams{ + Globals: map[string]string{ + "stats": "timeout 2m", + "tune.ssl.default-dh-param": "1024", + "nbproc": "1", + "nbthread": fmt.Sprint(runtime.GOMAXPROCS(0)), + "ulimit-n": "65536", + "maxconn": "32000", + }, + Defaults: map[string]string{ + "http-reuse": "always", + }, +} + const baseCfgTmpl = ` global master-worker stats socket {{.SocketPath}} mode 600 level admin expose-fd listeners - stats timeout 2m - tune.ssl.default-dh-param 1024 - nbproc 1 - nbthread {{.NbThread}} - ulimit-n 65536 + {{ range $k, $v := .HAProxyParams.Globals}} + {{$k}} {{$v}} + {{ end }} defaults - http-reuse always + {{ range $k, $v := .HAProxyParams.Defaults}} + {{$k}} {{$v}} + {{ end }} userlist controller user {{.DataplaneUser}} insecure-password {{.DataplanePass}} @@ -53,11 +68,10 @@ spoe-message check-intentions ` type baseParams struct { - NbThread int SocketPath string DataplaneUser string DataplanePass string - LogsPath string + HAProxyParams HAProxyParams } type haConfig struct { @@ -73,7 +87,7 @@ type haConfig struct { LogsSock string } -func newHaConfig(baseDir string, sd *lib.Shutdown) (*haConfig, error) { +func newHaConfig(baseDir string, params HAProxyParams, sd *lib.Shutdown) (*haConfig, error) { cfg := &haConfig{} sd.Add(1) @@ -119,11 +133,10 @@ func newHaConfig(baseDir string, sd *lib.Shutdown) (*haConfig, error) { cfg.DataplaneUser = "hapeoxy" err = tmpl.Execute(cfgFile, baseParams{ - NbThread: runtime.GOMAXPROCS(0), SocketPath: cfg.StatsSock, - LogsPath: cfg.LogsSock, DataplaneUser: cfg.DataplaneUser, DataplanePass: cfg.DataplanePass, + HAProxyParams: defaultsHAProxyParams.With(params), }) if err != nil { sd.Done() diff --git a/haproxy/haproxy.go b/haproxy/haproxy.go index fd4b625..d39df23 100644 --- a/haproxy/haproxy.go +++ b/haproxy/haproxy.go @@ -47,7 +47,7 @@ func New(consulClient *api.Client, cfg chan consul.Config, opts Options) *HAProx } func (h *HAProxy) Run(sd *lib.Shutdown) error { - hc, err := newHaConfig(h.opts.ConfigBaseDir, sd) + hc, err := newHaConfig(h.opts.ConfigBaseDir, h.opts.HAProxyParams, sd) if err != nil { return err } diff --git a/haproxy/options.go b/haproxy/options.go index e2a365f..9905f41 100644 --- a/haproxy/options.go +++ b/haproxy/options.go @@ -1,5 +1,30 @@ package haproxy +type HAProxyParams struct { + Defaults map[string]string + Globals map[string]string +} + +func (p HAProxyParams) With(other HAProxyParams) HAProxyParams { + new := HAProxyParams{ + Defaults: map[string]string{}, + Globals: map[string]string{}, + } + for k, v := range p.Defaults { + new.Defaults[k] = v + } + for k, v := range other.Defaults { + new.Defaults[k] = v + } + for k, v := range p.Globals { + new.Globals[k] = v + } + for k, v := range other.Globals { + new.Globals[k] = v + } + return new +} + type Options struct { HAProxyBin string DataplaneBin string @@ -9,4 +34,5 @@ type Options struct { StatsListenAddr string StatsRegisterService bool LogRequests bool + HAProxyParams HAProxyParams } diff --git a/main.go b/main.go index b5b0867..8bb1c69 100644 --- a/main.go +++ b/main.go @@ -60,6 +60,9 @@ func validateRequirements(dataplaneBin, haproxyBin string) error { } func main() { + haproxyParamsFlag := stringSliceFlag{} + + flag.Var(&haproxyParamsFlag, "haproxy-param", "Global or defaults Haproxy config parameter to set in config. Can be specified multiple times. Must be of the form `defaults.name=value` or `global.name=value`") versionFlag := flag.Bool("version", false, "Show version and exit") logLevel := flag.String("log-level", "INFO", "Log level") consulAddr := flag.String("http-addr", "127.0.0.1:8500", "Consul agent address") @@ -128,6 +131,11 @@ func main() { log.Fatalf("Please specify -sidecar-for or -sidecar-for-tag") } + haproxyParams, err := makeHAProxyParams(haproxyParamsFlag) + if err != nil { + log.Fatal(err) + } + consulLogger := &consulLogger{} watcher := consul.New(serviceID, consulClient, consulLogger) go func() { @@ -145,6 +153,7 @@ func main() { StatsListenAddr: *statsListenAddr, StatsRegisterService: *statsServiceRegister, LogRequests: ll == log.TraceLevel, + HAProxyParams: haproxyParams, }) sd.Add(1) go func() {