From c3999da376b2ac44cfa04cf74e662c0015e16f16 Mon Sep 17 00:00:00 2001 From: Michael Pleshakov Date: Fri, 14 Apr 2017 14:51:50 +0100 Subject: [PATCH] Add location-snippets, server-snippets and http-snippets for Plus --- .../controller/controller.go | 29 ++++++++++++++++--- nginx-plus-controller/nginx/config.go | 3 ++ nginx-plus-controller/nginx/configurator.go | 24 +++++++++++++-- nginx-plus-controller/nginx/convert.go | 6 ++-- nginx-plus-controller/nginx/convert_test.go | 26 +++++++++++++++-- nginx-plus-controller/nginx/ingress.tmpl | 11 +++++++ nginx-plus-controller/nginx/nginx.conf.tmpl | 5 ++++ nginx-plus-controller/nginx/nginx.go | 3 ++ 8 files changed, 95 insertions(+), 12 deletions(-) diff --git a/nginx-plus-controller/controller/controller.go b/nginx-plus-controller/controller/controller.go index 00a2a6f904..7549d6931f 100644 --- a/nginx-plus-controller/controller/controller.go +++ b/nginx-plus-controller/controller/controller.go @@ -379,14 +379,14 @@ func (lbc *LoadBalancerController) syncCfgm(key string) { if proxyReadTimeout, exists := cfgm.Data["proxy-read-timeout"]; exists { cfg.ProxyReadTimeout = proxyReadTimeout } - if proxyHideHeaders, exists, err := nginx.GetMapKeyAsStringSlice(cfgm.Data, "proxy-hide-headers", cfgm); exists { + if proxyHideHeaders, exists, err := nginx.GetMapKeyAsStringSlice(cfgm.Data, "proxy-hide-headers", cfgm, ","); exists { if err != nil { glog.Error(err) } else { cfg.ProxyHideHeaders = proxyHideHeaders } } - if proxyPassHeaders, exists, err := nginx.GetMapKeyAsStringSlice(cfgm.Data, "proxy-pass-headers", cfgm); exists { + if proxyPassHeaders, exists, err := nginx.GetMapKeyAsStringSlice(cfgm.Data, "proxy-pass-headers", cfgm, ","); exists { if err != nil { glog.Error(err) } else { @@ -409,7 +409,7 @@ func (lbc *LoadBalancerController) syncCfgm(key string) { cfg.HTTP2 = HTTP2 } } - if redirectToHTTPS, exists,err := nginx.GetMapKeyAsBool(cfgm.Data, "redirect-to-https", cfgm); exists { + if redirectToHTTPS, exists, err := nginx.GetMapKeyAsBool(cfgm.Data, "redirect-to-https", cfgm); exists { if err != nil { glog.Error(err) } else { @@ -461,7 +461,7 @@ func (lbc *LoadBalancerController) syncCfgm(key string) { if realIPHeader, exists := cfgm.Data["real-ip-header"]; exists { cfg.RealIPHeader = realIPHeader } - if setRealIPFrom, exists, err := nginx.GetMapKeyAsStringSlice(cfgm.Data, "set-real-ip-from", cfgm); exists { + if setRealIPFrom, exists, err := nginx.GetMapKeyAsStringSlice(cfgm.Data, "set-real-ip-from", cfgm, ","); exists { if err != nil { glog.Error(err) } else { @@ -519,6 +519,27 @@ func (lbc *LoadBalancerController) syncCfgm(key string) { if proxyMaxTempFileSize, exists := cfgm.Data["proxy-max-temp-file-size"]; exists { cfg.ProxyMaxTempFileSize = proxyMaxTempFileSize } + if mainHTTPSnippets, exists, err := nginx.GetMapKeyAsStringSlice(cfgm.Data, "http-snippets", cfgm, "\n"); exists { + if err != nil { + glog.Error(err) + } else { + cfg.MainHTTPSnippets = mainHTTPSnippets + } + } + if locationSnippets, exists, err := nginx.GetMapKeyAsStringSlice(cfgm.Data, "location-snippets", cfgm, "\n"); exists { + if err != nil { + glog.Error(err) + } else { + cfg.LocationSnippets = locationSnippets + } + } + if serverSnippets, exists, err := nginx.GetMapKeyAsStringSlice(cfgm.Data, "server-snippets", cfgm, "\n"); exists { + if err != nil { + glog.Error(err) + } else { + cfg.ServerSnippets = serverSnippets + } + } } lbc.cnf.UpdateConfig(cfg) diff --git a/nginx-plus-controller/nginx/config.go b/nginx-plus-controller/nginx/config.go index ee41d41434..4a9d60fe13 100644 --- a/nginx-plus-controller/nginx/config.go +++ b/nginx-plus-controller/nginx/config.go @@ -2,12 +2,15 @@ package nginx // Config holds NGINX configuration parameters type Config struct { + LocationSnippets []string + ServerSnippets []string ServerTokens string ProxyConnectTimeout string ProxyReadTimeout string ClientMaxBodySize string HTTP2 bool RedirectToHTTPS bool + MainHTTPSnippets []string MainServerNamesHashBucketSize string MainServerNamesHashMaxSize string MainLogFormat string diff --git a/nginx-plus-controller/nginx/configurator.go b/nginx-plus-controller/nginx/configurator.go index 31a8fc246d..cfa0ba69db 100644 --- a/nginx-plus-controller/nginx/configurator.go +++ b/nginx-plus-controller/nginx/configurator.go @@ -131,6 +131,7 @@ func (cnf *Configurator) generateNginxCfg(ingEx *IngressEx, pems map[string]stri RealIPRecursive: ingCfg.RealIPRecursive, ProxyHideHeaders: ingCfg.ProxyHideHeaders, ProxyPassHeaders: ingCfg.ProxyPassHeaders, + ServerSnippets: ingCfg.ServerSnippets, } if pemFile, ok := pems[serverName]; ok { @@ -188,6 +189,7 @@ func (cnf *Configurator) generateNginxCfg(ingEx *IngressEx, pems map[string]stri RealIPRecursive: ingCfg.RealIPRecursive, ProxyHideHeaders: ingCfg.ProxyHideHeaders, ProxyPassHeaders: ingCfg.ProxyPassHeaders, + ServerSnippets: ingCfg.ServerSnippets, } if pemFile, ok := pems[emptyHost]; ok { @@ -223,20 +225,34 @@ func (cnf *Configurator) createConfig(ingEx *IngressEx) Config { } } } + if serverSnippets, exists, err := GetMapKeyAsStringSlice(ingEx.Ingress.Annotations, "nginx.org/server-snippets", ingEx.Ingress, "\n"); exists { + if err != nil { + glog.Error(err) + } else { + ingCfg.ServerSnippets = serverSnippets + } + } + if locationSnippets, exists, err := GetMapKeyAsStringSlice(ingEx.Ingress.Annotations, "nginx.org/location-snippets", ingEx.Ingress, "\n"); exists { + if err != nil { + glog.Error(err) + } else { + ingCfg.LocationSnippets = locationSnippets + } + } if proxyConnectTimeout, exists := ingEx.Ingress.Annotations["nginx.org/proxy-connect-timeout"]; exists { ingCfg.ProxyConnectTimeout = proxyConnectTimeout } if proxyReadTimeout, exists := ingEx.Ingress.Annotations["nginx.org/proxy-read-timeout"]; exists { ingCfg.ProxyReadTimeout = proxyReadTimeout } - if proxyHideHeaders, exists, err := GetMapKeyAsStringSlice(ingEx.Ingress.Annotations, "nginx.org/proxy-hide-headers", ingEx.Ingress); exists { + if proxyHideHeaders, exists, err := GetMapKeyAsStringSlice(ingEx.Ingress.Annotations, "nginx.org/proxy-hide-headers", ingEx.Ingress, ","); exists { if err != nil { glog.Error(err) } else { ingCfg.ProxyHideHeaders = proxyHideHeaders } } - if proxyPassHeaders, exists, err := GetMapKeyAsStringSlice(ingEx.Ingress.Annotations, "nginx.org/proxy-pass-headers", ingEx.Ingress); exists { + if proxyPassHeaders, exists, err := GetMapKeyAsStringSlice(ingEx.Ingress.Annotations, "nginx.org/proxy-pass-headers", ingEx.Ingress, ","); exists { if err != nil { glog.Error(err) } else { @@ -253,7 +269,7 @@ func (cnf *Configurator) createConfig(ingEx *IngressEx) Config { ingCfg.HTTP2 = HTTP2 } } - if redirectToHTTPS, exists,err := GetMapKeyAsBool(ingEx.Ingress.Annotations, "nginx.org/redirect-to-https", ingEx.Ingress); exists { + if redirectToHTTPS, exists, err := GetMapKeyAsBool(ingEx.Ingress.Annotations, "nginx.org/redirect-to-https", ingEx.Ingress); exists { if err != nil { glog.Error(err) } else { @@ -416,6 +432,7 @@ func createLocation(path string, upstream Upstream, cfg *Config, websocket bool, ProxyBuffers: cfg.ProxyBuffers, ProxyBufferSize: cfg.ProxyBufferSize, ProxyMaxTempFileSize: cfg.ProxyMaxTempFileSize, + LocationSnippets: cfg.LocationSnippets, } return loc @@ -500,6 +517,7 @@ func (cnf *Configurator) UpdateConfig(config *Config) { cnf.config = config mainCfg := &NginxMainConfig{ + HTTPSnippets: config.MainHTTPSnippets, ServerNamesHashBucketSize: config.MainServerNamesHashBucketSize, ServerNamesHashMaxSize: config.MainServerNamesHashMaxSize, LogFormat: config.MainLogFormat, diff --git a/nginx-plus-controller/nginx/convert.go b/nginx-plus-controller/nginx/convert.go index adbede444e..44432479b2 100644 --- a/nginx-plus-controller/nginx/convert.go +++ b/nginx-plus-controller/nginx/convert.go @@ -40,10 +40,10 @@ func GetMapKeyAsInt(m map[string]string, key string, context apiObject) (int64, return 0, false, nil } -// GetMapKeyAsStringSlice tries to find and parse a key in the map as string slice splitting it on ',' -func GetMapKeyAsStringSlice(m map[string]string, key string, context apiObject) ([]string, bool, error) { +// GetMapKeyAsStringSlice tries to find and parse a key in the map as string slice splitting it on the delimiter +func GetMapKeyAsStringSlice(m map[string]string, key string, context apiObject, delimiter string) ([]string, bool, error) { if str, exists := m[key]; exists { - slice := strings.Split(str, ",") + slice := strings.Split(str, delimiter) return slice, exists, nil } return nil, false, nil diff --git a/nginx-plus-controller/nginx/convert_test.go b/nginx-plus-controller/nginx/convert_test.go index 01719efb20..a7c582928e 100644 --- a/nginx-plus-controller/nginx/convert_test.go +++ b/nginx-plus-controller/nginx/convert_test.go @@ -164,7 +164,7 @@ func TestGetMapKeyAsStringSlice(t *testing.T) { "key": "1.String,2.String,3.String", } - slice, exists, err := GetMapKeyAsStringSlice(configMap.Data, "key", &configMap) + slice, exists, err := GetMapKeyAsStringSlice(configMap.Data, "key", &configMap, ",") if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -178,11 +178,33 @@ func TestGetMapKeyAsStringSlice(t *testing.T) { } } +func TestGetMapKeyAsStringSliceMultilineSnippets(t *testing.T) { + configMap := configMap + configMap.Data = map[string]string{ + "server-snippets": ` + if ($new_uri) { + rewrite ^ $new_uri permanent; + }`, + } + slice, exists, err := GetMapKeyAsStringSlice(configMap.Data, "server-snippets", &configMap, "\n") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + if !exists { + t.Errorf("The key 'server-snippets' must exist in the configMap") + } + expected := []string{"", "\t\t\tif ($new_uri) {", "\t\t\t\trewrite ^ $new_uri permanent;", "\t\t\t}"} + t.Log(expected) + if !reflect.DeepEqual(expected, slice) { + t.Errorf("Unexpected return value:\nGot: %#v\nExpected: %#v", slice, expected) + } +} + func TestGetMapKeyAsStringSliceNotFound(t *testing.T) { configMap := configMap configMap.Data = map[string]string{} - _, exists, _ := GetMapKeyAsStringSlice(configMap.Data, "key", &configMap) + _, exists, _ := GetMapKeyAsStringSlice(configMap.Data, "key", &configMap, ",") if exists { t.Errorf("The key 'key' must not exist in the configMap") } diff --git a/nginx-plus-controller/nginx/ingress.tmpl b/nginx-plus-controller/nginx/ingress.tmpl index 18110d3254..51c40190a1 100644 --- a/nginx-plus-controller/nginx/ingress.tmpl +++ b/nginx-plus-controller/nginx/ingress.tmpl @@ -46,6 +46,11 @@ server { } {{- end}} + {{- if $server.ServerSnippets}} + {{range $value := $server.ServerSnippets}} + {{$value}}{{end}} + {{- end}} + {{range $location := $server.Locations}} location {{$location.Path}} { proxy_http_version 1.1; @@ -53,6 +58,12 @@ server { proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; {{end}} + + {{- if $location.LocationSnippets}} + {{range $value := $location.LocationSnippets}} + {{$value}}{{end}} + {{- end}} + proxy_connect_timeout {{$location.ProxyConnectTimeout}}; proxy_read_timeout {{$location.ProxyReadTimeout}}; client_max_body_size {{$location.ClientMaxBodySize}}; diff --git a/nginx-plus-controller/nginx/nginx.conf.tmpl b/nginx-plus-controller/nginx/nginx.conf.tmpl index d47dd9c0a6..73cee58a65 100644 --- a/nginx-plus-controller/nginx/nginx.conf.tmpl +++ b/nginx-plus-controller/nginx/nginx.conf.tmpl @@ -15,6 +15,11 @@ http { include /etc/nginx/mime.types; default_type application/octet-stream; + {{- if .HTTPSnippets}} + {{range $value := .HTTPSnippets}} + {{$value}}{{end}} + {{- end}} + {{if .LogFormat -}} log_format main '{{.LogFormat}}'; {{- else -}} diff --git a/nginx-plus-controller/nginx/nginx.go b/nginx-plus-controller/nginx/nginx.go index 71f580788f..e828dacdc7 100644 --- a/nginx-plus-controller/nginx/nginx.go +++ b/nginx-plus-controller/nginx/nginx.go @@ -41,6 +41,7 @@ type UpstreamServer struct { // Server describes an NGINX server type Server struct { + ServerSnippets []string Name string ServerTokens string Locations []Location @@ -65,6 +66,7 @@ type Server struct { // Location describes an NGINX location type Location struct { + LocationSnippets []string Path string Upstream Upstream ProxyConnectTimeout string @@ -85,6 +87,7 @@ type NginxMainConfig struct { ServerNamesHashMaxSize string LogFormat string HealthStatus bool + HTTPSnippets []string // http://nginx.org/en/docs/http/ngx_http_ssl_module.html SSLProtocols string SSLPreferServerCiphers bool