diff --git a/actions/reconfigure.go b/actions/reconfigure.go index 2c52bd05..2df9c110 100644 --- a/actions/reconfigure.go +++ b/actions/reconfigure.go @@ -15,11 +15,12 @@ import ( "sync" ) -const ServiceTemplateFeFilename = "service-formatted-fe.ctmpl" -const ServiceTemplateBeFilename = "service-formatted-be.ctmpl" +const serviceTemplateFeFilename = "service-formatted-fe.ctmpl" +const serviceTemplateBeFilename = "service-formatted-be.ctmpl" var mu = &sync.Mutex{} +// Methods that should be created for reconfigure actions type Reconfigurable interface { Executable GetData() (BaseReconfigure, proxy.Service) @@ -27,12 +28,14 @@ type Reconfigurable interface { GetTemplates(sr *proxy.Service) (front, back string, err error) } +// Data structure that holds reconfigure data type Reconfigure struct { BaseReconfigure proxy.Service Mode string `short:"m" long:"mode" env:"MODE" description:"If set to 'swarm', proxy will operate assuming that Docker service from v1.12+ is used."` } +// Base structure type BaseReconfigure struct { ConsulAddresses []string ConfigsPath string `short:"c" long:"configs-path" default:"/cfg" description:"The path to the configurations directory"` @@ -41,9 +44,13 @@ type BaseReconfigure struct { skipAddressValidation bool `env:"SKIP_ADDRESS_VALIDATION" description:"Whether to skip validating service address before reconfiguring the proxy."` } +// Singleton instance var ReconfigureInstance Reconfigure -// TODO: Change proxy.Service to *proxy.Service +/* +Creates new instance of the Reconfigurable interface +TODO: Change proxy.Service to *proxy.Service +*/ var NewReconfigure = func(baseData BaseReconfigure, serviceData proxy.Service, mode string) Reconfigurable { return &Reconfigure{ BaseReconfigure: baseData, @@ -209,9 +216,9 @@ func (m *Reconfigure) createConfigs(templatesPath string, sr *proxy.Service) err args := registry.CreateConfigsArgs{ Addresses: m.ConsulAddresses, TemplatesPath: templatesPath, - FeFile: ServiceTemplateFeFilename, + FeFile: serviceTemplateFeFilename, FeTemplate: feTemplate, - BeFile: ServiceTemplateBeFilename, + BeFile: serviceTemplateBeFilename, BeTemplate: beTemplate, ServiceName: sr.ServiceName, } diff --git a/actions/reconfigure_test.go b/actions/reconfigure_test.go index 3a4ca415..af6143bc 100644 --- a/actions/reconfigure_test.go +++ b/actions/reconfigure_test.go @@ -511,9 +511,9 @@ func (s ReconfigureTestSuite) Test_Execute_InvokesRegistrarableCreateConfigs() { expectedArgs := registry.CreateConfigsArgs{ Addresses: []string{s.ConsulAddress}, TemplatesPath: s.TemplatesPath, - FeFile: ServiceTemplateFeFilename, + FeFile: serviceTemplateFeFilename, FeTemplate: "", - BeFile: ServiceTemplateBeFilename, + BeFile: serviceTemplateBeFilename, BeTemplate: s.ConsulTemplateBe, ServiceName: s.ServiceName, } diff --git a/docs/config.md b/docs/config.md index 1686fc7e..9cb323db 100644 --- a/docs/config.md +++ b/docs/config.md @@ -16,6 +16,8 @@ The following environment variables can be used to configure the *Docker Flow Pr |CONNECTION_MODE |HAProxy supports 5 connection modes.

`http-keep-alive`: all requests and responses are processed.
`http-tunnel`: only the first request and response are processed, everything else is forwarded with no analysis.
`httpclose`: tunnel with "Connection: close" added in both directions.
`http-server-close`: the server-facing connection is closed after the response.
`forceclose`: the connection is actively closed after end of response.

In general, it is preferred to use `http-server-close` with application servers, and some static servers might benefit from `http-keep-alive`.|No|http-server-close|http-keep-alive| |DEBUG |Enables logging of each request sent through the proxy. Please consult [Debug Format](#debug-format) for info about the log entries. This feature should be used with caution. **Do not enable debugging in production unless necessary.**|No|false|true| |DEBUG_ERRORS_ONLY |If set to `true`, only requests that resulted in an error, timeout, retry, and redispatch will be logged. If a request is HTTP, responses with a status 5xx will be logged too. This variable will take effect only if `DEBUG` is set to `true`.|No|false|true| +|DEBUG_HTTP_FORMAT |Logging format that will be used with HTTP requests. Please consult [Custom log format](https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#8.2.4) for more info about the available options.|No| | | +|DEBUG_TCP_FORMAT |Logging format that will be used with TCP requests. Please consult [Custom log format](https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#8.2.4) for more info about the available options.|No| | | |DEFAULT_PORTS |The default ports used by the proxy. Multiple values can be separated with comma (`,`). If a port should be for SSL connections, append it with `:ssl.|No|80,443:ssl| | |EXTRA_FRONTEND |Value will be added to the default `frontend` configuration.|No | | | |EXTRA_GLOBAL |Value will be added to the default `global` configuration.|No | | | diff --git a/proxy/ha_proxy.go b/proxy/ha_proxy.go index 4a13efb9..d3ffa6ca 100644 --- a/proxy/ha_proxy.go +++ b/proxy/ha_proxy.go @@ -218,6 +218,13 @@ func (m HaProxy) getConfigData() ConfigData { d.ExtraFrontend += ` option httplog log global` + format := GetSecretOrEnvVar("DEBUG_HTTP_FORMAT", "") + if len(format) > 0 { + d.ExtraFrontend += fmt.Sprintf(` + log-format %s`, + format, + ) + } if strings.EqualFold(GetSecretOrEnvVar("DEBUG_ERRORS_ONLY", ""), "true") { d.ExtraDefaults += ` option dontlog-normal` @@ -345,6 +352,13 @@ frontend tcpFE_%d tmpl += ` option tcplog log global` + format := GetSecretOrEnvVar("DEBUG_TCP_FORMAT", "") + if len(format) > 0 { + tmpl += fmt.Sprintf(` + log-format %s`, + format, + ) + } } for _, s := range services { var backend string diff --git a/proxy/ha_proxy_test.go b/proxy/ha_proxy_test.go index 5d066f9f..48beb6db 100644 --- a/proxy/ha_proxy_test.go +++ b/proxy/ha_proxy_test.go @@ -311,6 +311,32 @@ func (s HaProxyTestSuite) Test_CreateConfigFromTemplates_AddsLogging_WhenDebug() s.Equal(expectedData, actualData) } +func (s HaProxyTestSuite) Test_CreateConfigFromTemplates_AddsHttpLogFormat_WhenSpecified() { + debugOrig := os.Getenv("DEBUG") + debugHttpFormatOrig := os.Getenv("DEBUG_HTTP_FORMAT") + defer func() { + os.Setenv("DEBUG", debugOrig) + os.Setenv("DEBUG_HTTP_FORMAT", debugHttpFormatOrig) + }() + os.Setenv("DEBUG", "true") + os.Setenv("DEBUG_HTTP_FORMAT", "something") + var actualData string + expectedData := fmt.Sprintf( + `%s + log-format something%s`, + s.getTemplateWithLogs(), + s.ServicesContent, + ) + writeFile = func(filename string, data []byte, perm os.FileMode) error { + actualData = string(data) + return nil + } + + NewHaProxy(s.TemplatesPath, s.ConfigsPath).CreateConfigFromTemplates() + + s.Equal(expectedData, actualData) +} + func (s HaProxyTestSuite) Test_CreateConfigFromTemplates_AddsDoNotLogNormal_WhenDebugErrorsOnlyIsSet() { debugOrig := os.Getenv("DEBUG") debugErrorsOnlyOrig := os.Getenv("DEBUG") @@ -677,6 +703,47 @@ frontend tcpFE_1234 s.Equal(expectedData, actualData) } +func (s HaProxyTestSuite) Test_CreateConfigFromTemplates_AddsTcpLoggingFormat() { + debugOrig := os.Getenv("DEBUG") + debugTcpFormatOrig := os.Getenv("DEBUG_TCP_FORMAT") + defer func() { + os.Setenv("DEBUG", debugOrig) + os.Setenv("DEBUG_TCP_FORMAT", debugTcpFormatOrig) + }() + os.Setenv("DEBUG", "true") + os.Setenv("DEBUG_TCP_FORMAT", "something-tcp-related") + var actualData string + expectedData := fmt.Sprintf( + `%s + +frontend tcpFE_1234 + bind *:1234 + mode tcp + option tcplog + log global + log-format something-tcp-related + default_backend my-service-1-be1234%s`, + s.getTemplateWithLogs(), + s.ServicesContent, + ) + writeFile = func(filename string, data []byte, perm os.FileMode) error { + actualData = string(data) + return nil + } + p := NewHaProxy(s.TemplatesPath, s.ConfigsPath) + data.Services["my-service-1"] = Service{ + ReqMode: "tcp", + ServiceName: "my-service-1", + ServiceDest: []ServiceDest{ + {SrcPort: 1234, Port: "4321"}, + }, + } + + p.CreateConfigFromTemplates() + + s.Equal(expectedData, actualData) +} + func (s HaProxyTestSuite) Test_CreateConfigFromTemplates_AddsContentFrontEndSNI() { var actualData string tmpl := s.TemplateContent