Skip to content

Commit

Permalink
Merge pull request #117 from rchicoli/add-template-options
Browse files Browse the repository at this point in the history
Add location-snippets, server-snippets and http-snippets
  • Loading branch information
pleshakov authored Feb 23, 2017
2 parents c63c31f + 03a7ce9 commit 7458904
Show file tree
Hide file tree
Showing 11 changed files with 125 additions and 11 deletions.
3 changes: 3 additions & 0 deletions examples/customization/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ The table below summarizes some of the options. More options (extensions) are av
| N/A | `real-ip-header` | Sets the value of the [real_ip_header](http://nginx.org/en/docs/http/ngx_http_realip_module.html#real_ip_header) directive. | `X-Real-IP`|
| N/A | `real-ip-recursive` | Enables or disables the [real_ip_recursive](http://nginx.org/en/docs/http/ngx_http_realip_module.html#real_ip_recursive) directive. | `False`|
| `nginx.org/server-tokens` | `server-tokens` | Enables or disables the [server_tokens](http://nginx.org/en/docs/http/ngx_http_core_module.html#server_tokens) directive. Additionally, with the NGINX Plus controller, you can specify a custom string value. The empty string value disables the emission of the “Server” field. | `True`|
| N/A | `http-snippets` | Sets a custom snippet in http context. | N/A |
| `nginx.org/location-snippets` | `location-snippets` | Sets a custom snippet in location context. | N/A |
| `nginx.org/server-snippets` | `server-snippets` | Sets a custom snippet in server context. | N/A |

## Using ConfigMaps

Expand Down
11 changes: 11 additions & 0 deletions examples/customization/cafe-ingress-with-annotations.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,17 @@ metadata:
nginx.org/proxy-connect-timeout: "30s"
nginx.org/proxy-read-timeout: "20s"
nginx.org/client-max-body-size: "4m"
nginx.org/location-snippets: |
if ($ssl_client_verify = SUCCESS) {
set $auth_basic off;
}
if ($ssl_client_verify != SUCCESS) {
set $auth_basic "Restricted";
}
auth_basic $auth_basic;
auth_basic_user_file "/var/run/secrets/nginx.org/auth-basic-file";
nginx.org/server-snippets: |
ssl_verify_client optional;
spec:
rules:
- host: cafe.example.com
Expand Down
12 changes: 12 additions & 0 deletions examples/customization/nginx-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,15 @@ data:
real-ip-header: "proxy_protocol" # default is X-Real-IP. Sets the value of the real_ip_header directive. http://nginx.org/en/docs/http/ngx_http_realip_module.html#real_ip_header
real-ip-recursive: "True" # default is "False". Enables or disables the real_ip_recursive directive. See http://nginx.org/en/docs/http/ngx_http_realip_module.html#real_ip_recursive
server-tokens: "False" # default is "True". Enables or disables the server_tokens directive. See http://nginx.org/en/docs/http/ngx_http_core_module.html#server_tokens
http-snippets: | # Pipe is used for multiple line snippets. Make sure the snippet is not a default value, in order to avoid duplication.
map $uri $new_uri {
/old.html /index.html;
}
server-snippets: | # No default. Pipe is used for multiple line snippets. Make sure the snippet is not a default value, in order to avoid duplication.
# Old website redirect
if ($new_uri) {
rewrite ^ $new_uri permanent;
}
location-snippets: | # No default. Pipe is used for multiple line snippets. Make sure the snippet is not a default value, in order to avoid duplication.
proxy_temp_path /var/nginx/proxy_temp;
charset koi8-r;
31 changes: 27 additions & 4 deletions nginx-controller/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -375,14 +375,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 {
Expand All @@ -405,7 +405,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 {
Expand Down Expand Up @@ -457,7 +457,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 {
Expand Down Expand Up @@ -515,6 +515,29 @@ 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)

Expand Down
3 changes: 3 additions & 0 deletions nginx-controller/nginx/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ package nginx

// Config holds NGINX configuration parameters
type Config struct {
LocationSnippets []string
ServerSnippets []string
ServerTokens bool
ProxyConnectTimeout string
ProxyReadTimeout string
ClientMaxBodySize string
HTTP2 bool
RedirectToHTTPS bool
MainHTTPSnippets []string
MainServerNamesHashBucketSize string
MainServerNamesHashMaxSize string
MainLogFormat string
Expand Down
24 changes: 22 additions & 2 deletions nginx-controller/nginx/configurator.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,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 {
Expand Down Expand Up @@ -173,6 +174,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 {
Expand Down Expand Up @@ -204,20 +206,36 @@ func (cnf *Configurator) createConfig(ingEx *IngressEx) Config {
ingCfg.ServerTokens = serverTokens
}
}

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 {
Expand Down Expand Up @@ -366,6 +384,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
Expand Down Expand Up @@ -433,6 +452,7 @@ func (cnf *Configurator) UpdateConfig(config *Config) {

cnf.config = config
mainCfg := &NginxMainConfig{
HTTPSnippets: config.MainHTTPSnippets,
ServerNamesHashBucketSize: config.MainServerNamesHashBucketSize,
ServerNamesHashMaxSize: config.MainServerNamesHashMaxSize,
LogFormat: config.MainLogFormat,
Expand Down
6 changes: 3 additions & 3 deletions nginx-controller/nginx/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 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
Expand Down
27 changes: 25 additions & 2 deletions nginx-controller/nginx/convert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand All @@ -176,13 +176,36 @@ func TestGetMapKeyAsStringSlice(t *testing.T) {
if !reflect.DeepEqual(expected, slice) {
t.Errorf("Unexpected return value:\nGot: %#v\nExpected: %#v", slice, expected)
}

}

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")
}
Expand Down
11 changes: 11 additions & 0 deletions nginx-controller/nginx/ingress.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,24 @@ server {
}
{{- end}}

{{- if $server.ServerSnippets}}
{{range $value := $server.ServerSnippets}}
{{$value}}{{end}}
{{- end}}

{{range $location := $server.Locations}}
location {{$location.Path}} {
proxy_http_version 1.1;
{{if $location.Websocket}}
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}};
Expand Down
5 changes: 5 additions & 0 deletions nginx-controller/nginx/nginx.conf.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -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 -}}
Expand Down
3 changes: 3 additions & 0 deletions nginx-controller/nginx/nginx.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ type UpstreamServer struct {

// Server describes an NGINX server
type Server struct {
ServerSnippets []string
Name string
ServerTokens bool
Locations []Location
Expand All @@ -63,6 +64,7 @@ type Server struct {

// Location describes an NGINX location
type Location struct {
LocationSnippets []string
Path string
Upstream Upstream
ProxyConnectTimeout string
Expand All @@ -83,6 +85,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
Expand Down

0 comments on commit 7458904

Please sign in to comment.