From aa191c8c9be35c4760f61b437bc880d6a4a2d66e Mon Sep 17 00:00:00 2001 From: Arno Uhlig Date: Fri, 1 Sep 2017 17:43:11 +0200 Subject: [PATCH] configurable proxy-request-buffering per location and fix conectTimeout -> connectTimeout --- controllers/nginx/configuration.md | 3 ++ controllers/nginx/pkg/config/config.go | 1 + .../rootfs/etc/nginx/template/nginx.tmpl | 1 + core/pkg/ingress/annotations/proxy/main.go | 49 ++++++++++++------- .../ingress/annotations/proxy/main_test.go | 8 +++ core/pkg/ingress/defaults/main.go | 4 ++ 6 files changed, 47 insertions(+), 19 deletions(-) diff --git a/controllers/nginx/configuration.md b/controllers/nginx/configuration.md index 258e201ab4..683de887f6 100644 --- a/controllers/nginx/configuration.md +++ b/controllers/nginx/configuration.md @@ -395,6 +395,8 @@ log-format-upstream: '{ "time": "$time_iso8601", "remote_addr": "$proxy_protocol **proxy-next-upstream:** Specifies in [which cases](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream) a request should be passed to the next server. +**proxy-request-buffering:** Enables or disables [buffering of a client request body](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_request_buffering). + **retry-non-idempotent:** Since 1.9.13 NGINX will not retry non-idempotent requests (POST, LOCK, PATCH) in case of an error in the upstream server. The previous behavior can be restored using the value "true". @@ -510,6 +512,7 @@ The following table shows the options, the default value and a description. |max-worker-connections|"16384"| |proxy-body-size|same as body-size| |proxy-buffer-size|"4k"| +|proxy-request-buffering|"on"| |proxy-connect-timeout|"5"| |proxy-cookie-domain|"off"| |proxy-cookie-path|"off"| diff --git a/controllers/nginx/pkg/config/config.go b/controllers/nginx/pkg/config/config.go index e97df3f2c7..4bb53b0db7 100644 --- a/controllers/nginx/pkg/config/config.go +++ b/controllers/nginx/pkg/config/config.go @@ -422,6 +422,7 @@ func NewDefault() Configuration { ProxyCookieDomain: "off", ProxyCookiePath: "off", ProxyNextUpstream: "error timeout invalid_header http_502 http_503 http_504", + ProxyRequestBuffering: "on", SSLRedirect: true, CustomHTTPErrors: []int{}, WhitelistSourceRange: []string{}, diff --git a/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl b/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl index 4ebb8c8a5a..e137841266 100644 --- a/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl +++ b/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl @@ -740,6 +740,7 @@ stream { proxy_buffering off; proxy_buffer_size "{{ $location.Proxy.BufferSize }}"; proxy_buffers 4 "{{ $location.Proxy.BufferSize }}"; + proxy_request_buffering "{{ $location.Proxy.RequestBuffering }}"; proxy_http_version 1.1; diff --git a/core/pkg/ingress/annotations/proxy/main.go b/core/pkg/ingress/annotations/proxy/main.go index 568a75dd44..e31fb4ba7a 100644 --- a/core/pkg/ingress/annotations/proxy/main.go +++ b/core/pkg/ingress/annotations/proxy/main.go @@ -24,28 +24,30 @@ import ( ) const ( - bodySize = "ingress.kubernetes.io/proxy-body-size" - connect = "ingress.kubernetes.io/proxy-connect-timeout" - send = "ingress.kubernetes.io/proxy-send-timeout" - read = "ingress.kubernetes.io/proxy-read-timeout" - bufferSize = "ingress.kubernetes.io/proxy-buffer-size" - cookiePath = "ingress.kubernetes.io/proxy-cookie-path" - cookieDomain = "ingress.kubernetes.io/proxy-cookie-domain" - nextUpstream = "ingress.kubernetes.io/proxy-next-upstream" - passParams = "ingress.kubernetes.io/proxy-pass-params" + bodySize = "ingress.kubernetes.io/proxy-body-size" + connect = "ingress.kubernetes.io/proxy-connect-timeout" + send = "ingress.kubernetes.io/proxy-send-timeout" + read = "ingress.kubernetes.io/proxy-read-timeout" + bufferSize = "ingress.kubernetes.io/proxy-buffer-size" + cookiePath = "ingress.kubernetes.io/proxy-cookie-path" + cookieDomain = "ingress.kubernetes.io/proxy-cookie-domain" + nextUpstream = "ingress.kubernetes.io/proxy-next-upstream" + passParams = "ingress.kubernetes.io/proxy-pass-params" + requestBuffering = "ingress.kubernetes.io/proxy-request-buffering" ) // Configuration returns the proxy timeout to use in the upstream server/s type Configuration struct { - BodySize string `json:"bodySize"` - ConnectTimeout int `json:"conectTimeout"` - SendTimeout int `json:"sendTimeout"` - ReadTimeout int `json:"readTimeout"` - BufferSize string `json:"bufferSize"` - CookieDomain string `json:"cookieDomain"` - CookiePath string `json:"cookiePath"` - NextUpstream string `json:"nextUpstream"` - PassParams string `json:"passParams"` + BodySize string `json:"bodySize"` + ConnectTimeout int `json:"connectTimeout"` + SendTimeout int `json:"sendTimeout"` + ReadTimeout int `json:"readTimeout"` + BufferSize string `json:"bufferSize"` + CookieDomain string `json:"cookieDomain"` + CookiePath string `json:"cookiePath"` + NextUpstream string `json:"nextUpstream"` + PassParams string `json:"passParams"` + RequestBuffering string `json:"requestBuffering"` } // Equal tests for equality between two Configuration types @@ -84,6 +86,10 @@ func (l1 *Configuration) Equal(l2 *Configuration) bool { return false } + if l1.RequestBuffering != l2.RequestBuffering { + return false + } + return true } @@ -145,5 +151,10 @@ func (a proxy) Parse(ing *extensions.Ingress) (interface{}, error) { pp = defBackend.ProxyPassParams } - return &Configuration{bs, ct, st, rt, bufs, cd, cp, nu, pp}, nil + rb, err := parser.GetStringAnnotation(requestBuffering, ing) + if err != nil || rb == "" { + rb = defBackend.ProxyRequestBuffering + } + + return &Configuration{bs, ct, st, rt, bufs, cd, cp, nu, pp, rb}, nil } diff --git a/core/pkg/ingress/annotations/proxy/main_test.go b/core/pkg/ingress/annotations/proxy/main_test.go index 76481a7301..8700457f13 100644 --- a/core/pkg/ingress/annotations/proxy/main_test.go +++ b/core/pkg/ingress/annotations/proxy/main_test.go @@ -75,6 +75,7 @@ func (m mockBackend) GetDefaultBackend() defaults.Backend { ProxyBodySize: "3k", ProxyNextUpstream: "error", ProxyPassParams: "nocanon keepalive=On", + ProxyRequestBuffering: "on", } } @@ -89,6 +90,7 @@ func TestProxy(t *testing.T) { data[bodySize] = "2k" data[nextUpstream] = "off" data[passParams] = "smax=5 max=10" + data[requestBuffering] = "off" ing.SetAnnotations(data) i, err := NewParser(mockBackend{}).Parse(ing) @@ -120,6 +122,9 @@ func TestProxy(t *testing.T) { if p.PassParams != "smax=5 max=10" { t.Errorf("expected \"smax=5 max=10\" as pass-params but returned \"%v\"", p.PassParams) } + if p.RequestBuffering != "off" { + t.Errorf("expected off as request-buffering but returned %v", p.RequestBuffering) + } } func TestProxyWithNoAnnotation(t *testing.T) { @@ -157,4 +162,7 @@ func TestProxyWithNoAnnotation(t *testing.T) { if p.PassParams != "nocanon keepalive=On" { t.Errorf("expected \"nocanon keepalive=On\" as pass-params but returned \"%v\"", p.PassParams) } + if p.RequestBuffering != "on" { + t.Errorf("expected on as request-buffering but returned %v", p.RequestBuffering) + } } diff --git a/core/pkg/ingress/defaults/main.go b/core/pkg/ingress/defaults/main.go index 5b50ca9bab..20b0a89fb2 100644 --- a/core/pkg/ingress/defaults/main.go +++ b/core/pkg/ingress/defaults/main.go @@ -56,6 +56,10 @@ type Backend struct { // Parameters for proxy-pass directive (eg. Apache web server). ProxyPassParams string `json:"proxy-pass-params"` + // Enables or disables buffering of a client request body. + // http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_request_buffering + ProxyRequestBuffering string `json:"proxy-request-buffering"` + // Name server/s used to resolve names of upstream servers into IP addresses. // The file /etc/resolv.conf is used as DNS resolution configuration. Resolver []net.IP