Add Generic interface

This commit is contained in:
Manuel de Brito Fontes 2016-11-16 15:24:26 -03:00
parent f2b627486d
commit 5a8e090736
36 changed files with 58014 additions and 675 deletions

View file

@ -25,14 +25,16 @@ import (
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/api"
"k8s.io/ingress/core/pkg/ingress"
"k8s.io/ingress/core/pkg/ingress/defaults"
"errors"
"k8s.io/ingress/controllers/nginx/pkg/config"
ngx_template "k8s.io/ingress/controllers/nginx/pkg/template"
"k8s.io/ingress/controllers/nginx/pkg/version"
"k8s.io/kubernetes/pkg/api"
)
var (
@ -75,6 +77,8 @@ Error loading new template : %v
}
n.t = ngxTpl
go n.Start()
return n
}
@ -85,7 +89,7 @@ type NGINXController struct {
binary string
}
// Start ...
// Start start a new NGINX master process running in foreground.
func (n NGINXController) Start() {
glog.Info("starting NGINX process...")
cmd := exec.Command(n.binary, "-c", cfgPath)
@ -99,14 +103,13 @@ func (n NGINXController) Start() {
}
}
// Stop ...
func (n NGINXController) Stop() error {
n.t.Close()
return exec.Command(n.binary, "-s", "stop").Run()
}
// Reload checks if the running configuration file is different
// to the specified and reload nginx if required
func (n NGINXController) Reload(data []byte) ([]byte, error) {
if !n.isReloadRequired(data) {
return nil, fmt.Errorf("Reload not required")
}
// Restart ...
func (n NGINXController) Restart(data []byte) ([]byte, error) {
err := ioutil.WriteFile(cfgPath, data, 0644)
if err != nil {
return nil, err
@ -120,15 +123,15 @@ func (n NGINXController) Test(file string) *exec.Cmd {
return exec.Command(n.binary, "-t", "-c", file)
}
// UpstreamDefaults returns the nginx defaults
func (n NGINXController) UpstreamDefaults() defaults.Backend {
// BackendDefaults returns the nginx defaults
func (n NGINXController) BackendDefaults() defaults.Backend {
d := config.NewDefault()
return d.Backend
}
// IsReloadRequired check if the new configuration file is different
// from the current one.
func (n NGINXController) IsReloadRequired(data []byte) bool {
func (n NGINXController) isReloadRequired(data []byte) bool {
in, err := os.Open(cfgPath)
if err != nil {
return false
@ -167,8 +170,13 @@ func (n NGINXController) IsReloadRequired(data []byte) bool {
}
// Info return build information
func (n NGINXController) Info() string {
return fmt.Sprintf("build version %v from repo %v commit %v", version.RELEASE, version.REPO, version.COMMIT)
func (n NGINXController) Info() *ingress.BackendInfo {
return &ingress.BackendInfo{
Name: "NGINX",
Release: version.RELEASE,
Build: version.COMMIT,
Repository: version.REPO,
}
}
// testTemplate checks if the NGINX configuration inside the byte array is valid
@ -183,12 +191,13 @@ func (n NGINXController) testTemplate(cfg []byte) error {
out, err := n.Test(tmpfile.Name()).CombinedOutput()
if err != nil {
// this error is different from the rest because it must be clear why nginx is not working
return fmt.Errorf(`
oe := fmt.Sprintf(`
-------------------------------------------------------------------------------
Error: %v
%v
-------------------------------------------------------------------------------
`, err, string(out))
return errors.New(oe)
}
os.Remove(tmpfile.Name())
@ -207,9 +216,9 @@ func (n NGINXController) OnUpdate(cmap *api.ConfigMap, ingressCfg ingress.Config
var longestName int
var serverNames int
for _, srv := range ingressCfg.Servers {
serverNames += len([]byte(srv.Name))
if longestName < len(srv.Name) {
longestName = len(srv.Name)
serverNames += len([]byte(srv.Hostname))
if longestName < len(srv.Hostname) {
longestName = len(srv.Hostname)
}
}
@ -234,21 +243,17 @@ func (n NGINXController) OnUpdate(cmap *api.ConfigMap, ingressCfg ingress.Config
cfg.ServerNameHashMaxSize = serverNameHashMaxSize
}
conf := make(map[string]interface{})
// adjust the size of the backlog
conf["backlogSize"] = sysctlSomaxconn()
conf["upstreams"] = ingressCfg.Upstreams
conf["passthroughUpstreams"] = ingressCfg.PassthroughUpstreams
conf["servers"] = ingressCfg.Servers
conf["tcpUpstreams"] = ingressCfg.TCPEndpoints
conf["udpUpstreams"] = ingressCfg.UPDEndpoints
conf["healthzURL"] = ingressCfg.HealthzURL
conf["defResolver"] = cfg.Resolver
conf["sslDHParam"] = ""
conf["customErrors"] = len(cfg.CustomHTTPErrors) > 0
conf["cfg"] = ngx_template.StandarizeKeyNames(cfg)
return n.t.Write(conf, n.testTemplate)
return n.t.Write(config.TemplateConfig{
BacklogSize: sysctlSomaxconn(),
Backends: ingressCfg.Backends,
PassthrougBackends: ingressCfg.PassthroughBackends,
Servers: ingressCfg.Servers,
TCPBackends: ingressCfg.TCPEndpoints,
UDPBackends: ingressCfg.UPDEndpoints,
HealthzURI: "/healthz",
CustomErrors: len(cfg.CustomHTTPErrors) > 0,
Cfg: cfg,
}, n.testTemplate)
}
// http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2

View file

@ -19,9 +19,10 @@ package config
import (
"runtime"
"k8s.io/ingress/core/pkg/ingress/defaults"
"github.com/golang/glog"
"k8s.io/ingress/core/pkg/ingress"
"k8s.io/ingress/core/pkg/ingress/defaults"
)
const (
@ -216,8 +217,7 @@ type Configuration struct {
WorkerProcesses int `structs:"worker-processes,omitempty"`
}
// NewDefault returns the default configuration contained
// in the file default-conf.json
// NewDefault returns the default nginx configuration
func NewDefault() Configuration {
cfg := Configuration{
BodySize: bodySize,
@ -264,3 +264,15 @@ func NewDefault() Configuration {
return cfg
}
type TemplateConfig struct {
BacklogSize int
Backends []*ingress.Backend
PassthrougBackends []*ingress.SSLPassthroughBackend
Servers []*ingress.Server
TCPBackends []*ingress.Location
UDPBackends []*ingress.Location
HealthzURI string
CustomErrors bool
Cfg Configuration
}

View file

@ -27,10 +27,10 @@ import (
"github.com/mitchellh/mapstructure"
go_camelcase "github.com/segmentio/go-camelcase"
"k8s.io/kubernetes/pkg/api"
"k8s.io/ingress/controllers/nginx/pkg/config"
"k8s.io/ingress/core/pkg/ingress/defaults"
"k8s.io/kubernetes/pkg/api"
)
const (
@ -50,9 +50,9 @@ func ReadConfig(conf *api.ConfigMap) config.Configuration {
return config.NewDefault()
}
var errors []int
var skipUrls []string
var whitelist []string
errors := make([]int, 0)
skipUrls := make([]string, 0)
whitelist := make([]string, 0)
if val, ok := conf.Data[customHTTPErrors]; ok {
delete(conf.Data, customHTTPErrors)

View file

@ -27,6 +27,7 @@ import (
"github.com/golang/glog"
"k8s.io/ingress/controllers/nginx/pkg/config"
"k8s.io/ingress/core/pkg/ingress"
"k8s.io/ingress/core/pkg/watch"
)
@ -73,12 +74,19 @@ func (t *Template) Close() {
// Write populates a buffer using a template with NGINX configuration
// and the servers and upstreams created by Ingress rules
func (t *Template) Write(conf map[string]interface{},
isValidTemplate func([]byte) error) ([]byte, error) {
func (t *Template) Write(conf config.TemplateConfig, isValidTemplate func([]byte) error) ([]byte, error) {
defer t.tmplBuf.Reset()
defer t.outCmdBuf.Reset()
defer func() {
if t.s < t.tmplBuf.Cap() {
glog.V(2).Infof("adjusting template buffer size from %v to %v", t.s, t.tmplBuf.Cap())
t.s = t.tmplBuf.Cap()
t.tmplBuf = bytes.NewBuffer(make([]byte, 0, t.tmplBuf.Cap()))
t.outCmdBuf = bytes.NewBuffer(make([]byte, 0, t.outCmdBuf.Cap()))
}
}()
if glog.V(3) {
b, err := json.Marshal(conf)
if err != nil {
@ -88,12 +96,8 @@ func (t *Template) Write(conf map[string]interface{},
}
err := t.tmpl.Execute(t.tmplBuf, conf)
if t.s < t.tmplBuf.Cap() {
glog.V(2).Infof("adjusting template buffer size from %v to %v", t.s, t.tmplBuf.Cap())
t.s = t.tmplBuf.Cap()
t.tmplBuf = bytes.NewBuffer(make([]byte, 0, t.tmplBuf.Cap()))
t.outCmdBuf = bytes.NewBuffer(make([]byte, 0, t.outCmdBuf.Cap()))
if err != nil {
return nil, err
}
// squeezes multiple adjacent empty lines to be single
@ -124,12 +128,12 @@ var (
}
return true
},
"buildLocation": buildLocation,
"buildAuthLocation": buildAuthLocation,
"buildProxyPass": buildProxyPass,
"buildRateLimitZones": buildRateLimitZones,
"buildRateLimit": buildRateLimit,
"getSSPassthroughUpstream": getSSPassthroughUpstream,
"buildLocation": buildLocation,
"buildAuthLocation": buildAuthLocation,
"buildProxyPass": buildProxyPass,
"buildRateLimitZones": buildRateLimitZones,
"buildRateLimit": buildRateLimit,
"buildSSPassthroughUpstreams": buildSSPassthroughUpstreams,
"contains": strings.Contains,
"hasPrefix": strings.HasPrefix,
@ -139,13 +143,32 @@ var (
}
)
func getSSPassthroughUpstream(input interface{}) string {
s, ok := input.(*ingress.Server)
if !ok {
return ""
func buildSSPassthroughUpstreams(b interface{}, sslb interface{}) string {
backends := b.([]*ingress.Backend)
sslBackends := sslb.([]*ingress.SSLPassthroughBackend)
buf := bytes.NewBuffer(make([]byte, 0, 10))
// multiple services can use the same upstream.
// avoid duplications using a map[name]=true
u := make(map[string]bool)
for _, passthrough := range sslBackends {
if u[passthrough.Backend] {
continue
}
u[passthrough.Backend] = true
fmt.Fprintf(buf, "upstream %v {\n", passthrough.Backend)
for _, backend := range backends {
if backend.Name == passthrough.Backend {
for _, server := range backend.Endpoints {
fmt.Fprintf(buf, "\t\tserver %v:%v;\n", server.Address, server.Port)
}
break
}
}
fmt.Fprint(buf, "\t}\n\n")
}
return s.Name
return buf.String()
}
// buildLocation produces the location string, if the ingress has redirects
@ -184,20 +207,27 @@ func buildAuthLocation(input interface{}) string {
// (specified through the ingress.kubernetes.io/rewrite-to annotation)
// If the annotation ingress.kubernetes.io/add-base-url:"true" is specified it will
// add a base tag in the head of the response from the service
func buildProxyPass(input interface{}) string {
location, ok := input.(*ingress.Location)
func buildProxyPass(b interface{}, loc interface{}) string {
backends := b.([]*ingress.Backend)
location, ok := loc.(*ingress.Location)
if !ok {
return ""
}
path := location.Path
proto := "http"
if location.SecureUpstream {
proto = "https"
for _, backend := range backends {
if backend.Name == location.Backend {
if backend.Secure {
proto = "https"
}
break
}
}
// defProxyPass returns the default proxy_pass, just the name of the upstream
defProxyPass := fmt.Sprintf("proxy_pass %s://%s;", proto, location.Backend.Name)
defProxyPass := fmt.Sprintf("proxy_pass %s://%s;", proto, location.Backend)
// if the path in the ingress rule is equals to the target: no special rewrite
if path == location.Redirect.Target {
return defProxyPass
@ -227,13 +257,13 @@ func buildProxyPass(input interface{}) string {
rewrite %s(.*) /$1 break;
rewrite %s / break;
proxy_pass %s://%s;
%v`, path, location.Path, proto, location.Backend.Name, abu)
%v`, path, location.Path, proto, location.Backend, abu)
}
return fmt.Sprintf(`
rewrite %s(.*) %s/$1 break;
proxy_pass %s://%s;
%v`, path, location.Redirect.Target, proto, location.Backend.Name, abu)
%v`, path, location.Redirect.Target, proto, location.Backend, abu)
}
// default proxy_pass

View file

@ -17,14 +17,21 @@ limitations under the License.
package template
import (
"encoding/json"
"os"
"path"
"strings"
"testing"
"io/ioutil"
"k8s.io/ingress/controllers/nginx/pkg/config"
"k8s.io/ingress/core/pkg/ingress"
"k8s.io/ingress/core/pkg/ingress/annotations/rewrite"
)
var (
// TODO: add tests for secure endpoints
tmplFuncTestcases = map[string]struct {
Path string
Target string
@ -88,12 +95,77 @@ func TestBuildProxyPass(t *testing.T) {
loc := &ingress.Location{
Path: tc.Path,
Redirect: rewrite.Redirect{Target: tc.Target, AddBaseURL: tc.AddBaseURL},
Upstream: ingress.Backend{Name: "upstream-name"},
Backend: "upstream-name",
}
pp := buildProxyPass(loc)
pp := buildProxyPass([]*ingress.Backend{}, loc)
if !strings.EqualFold(tc.ProxyPass, pp) {
t.Errorf("%s: expected \n'%v'\nbut returned \n'%v'", k, tc.ProxyPass, pp)
}
}
}
func TestTemplateWithData(t *testing.T) {
pwd, _ := os.Getwd()
f, err := os.Open(path.Join(pwd, "../../test/data/config.json"))
if err != nil {
t.Errorf("unexpected error reading json file: %v", err)
}
defer f.Close()
data, err := ioutil.ReadFile(f.Name())
if err != nil {
t.Error("unexpected error reading json file: ", err)
}
var dat config.TemplateConfig
if err := json.Unmarshal(data, &dat); err != nil {
t.Errorf("unexpected error unmarshalling json: %v", err)
}
tf, err := os.Open(path.Join(pwd, "../../rootfs/etc/nginx/template/nginx.tmpl"))
if err != nil {
t.Errorf("unexpected error reading json file: %v", err)
}
defer tf.Close()
ngxTpl, err := NewTemplate(tf.Name(), func() {})
if err != nil {
t.Errorf("invalid NGINX template: %v", err)
}
_, err = ngxTpl.Write(dat, func(b []byte) error { return nil })
if err != nil {
t.Errorf("invalid NGINX template: %v", err)
}
}
func BenchmarkTemplateWithData(b *testing.B) {
pwd, _ := os.Getwd()
f, err := os.Open(path.Join(pwd, "../../test/data/config.json"))
if err != nil {
b.Errorf("unexpected error reading json file: %v", err)
}
defer f.Close()
data, err := ioutil.ReadFile(f.Name())
if err != nil {
b.Error("unexpected error reading json file: ", err)
}
var dat config.TemplateConfig
if err := json.Unmarshal(data, &dat); err != nil {
b.Errorf("unexpected error unmarshalling json: %v", err)
}
tf, err := os.Open(path.Join(pwd, "../../rootfs/etc/nginx/template/nginx.tmpl"))
if err != nil {
b.Errorf("unexpected error reading json file: %v", err)
}
defer tf.Close()
ngxTpl, err := NewTemplate(tf.Name(), func() {})
if err != nil {
b.Errorf("invalid NGINX template: %v", err)
}
for i := 0; i < b.N; i++ {
ngxTpl.Write(dat, func(b []byte) error { return nil })
}
}

View file

@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
FROM gcr.io/google_containers/nginx-slim:0.10
FROM gcr.io/google_containers/nginx-slim:0.11
RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y \
diffutils \

View file

@ -1,20 +1,20 @@
{{ $cfg := .cfg }}{{ $healthzURL := .healthzURL }}
{{ $cfg := .Cfg }}{{ $healthzURI := .HealthzURI }}{{ $backends := .Backends }}
daemon off;
worker_processes {{ $cfg.workerProcesses }};
worker_processes {{ $cfg.WorkerProcesses }};
pid /run/nginx.pid;
worker_rlimit_nofile 131072;
events {
multi_accept on;
worker_connections {{ $cfg.maxWorkerConnections }};
worker_connections {{ $cfg.MaxWorkerConnections }};
use epoll;
}
http {
{{/* we use the value of the header X-Forwarded-For to be able to use the geo_ip module */}}
{{ if $cfg.useProxyProtocol }}
set_real_ip_from {{ $cfg.proxyRealIpCidr }};
{{ if $cfg.UseProxyProtocol }}
set_real_ip_from {{ $cfg.ProxyRealIpCidr }};
real_ip_header proxy_protocol;
{{ else }}
real_ip_header X-Forwarded-For;
@ -30,8 +30,8 @@ http {
geoip_city /etc/nginx/GeoLiteCity.dat;
geoip_proxy_recursive on;
{{ if $cfg.enableVtsStatus }}
vhost_traffic_status_zone shared:vhost_traffic_status:{{ $cfg.vtsStatusZoneSize }};
{{ if $cfg.EnableVtsStatus }}
vhost_traffic_status_zone shared:vhost_traffic_status:{{ $cfg.VtsStatusZoneSize }};
vhost_traffic_status_filter_by_set_key $geoip_country_code country::*;
{{ end }}
@ -50,43 +50,43 @@ http {
reset_timedout_connection on;
keepalive_timeout {{ $cfg.keepAlive }}s;
keepalive_timeout {{ $cfg.KeepAlive }}s;
types_hash_max_size 2048;
server_names_hash_max_size {{ $cfg.serverNameHashMaxSize }};
server_names_hash_bucket_size {{ $cfg.serverNameHashBucketSize }};
map_hash_bucket_size {{ $cfg.mapHashBucketSize }};
server_names_hash_max_size {{ $cfg.ServerNameHashMaxSize }};
server_names_hash_bucket_size {{ $cfg.ServerNameHashBucketSize }};
map_hash_bucket_size {{ $cfg.MapHashBucketSize }};
include /etc/nginx/mime.types;
default_type text/html;
{{ if $cfg.useGzip }}
{{ if $cfg.UseGzip }}
gzip on;
gzip_comp_level 5;
gzip_http_version 1.1;
gzip_min_length 256;
gzip_types {{ $cfg.gzipTypes }};
gzip_types {{ $cfg.GzipTypes }};
gzip_proxied any;
{{ end }}
client_max_body_size "{{ $cfg.bodySize }}";
client_max_body_size "{{ $cfg.BodySize }}";
log_format upstreaminfo '{{ if $cfg.useProxyProtocol }}$proxy_protocol_addr{{ else }}$remote_addr{{ end }} - '
log_format upstreaminfo '{{ if $cfg.UseProxyProtocol }}$proxy_protocol_addr{{ else }}$remote_addr{{ end }} - '
'[$proxy_add_x_forwarded_for] - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" '
'$request_length $request_time [$proxy_upstream_name] $upstream_addr $upstream_response_length $upstream_response_time $upstream_status';
{{/* map urls that should not appear in access.log */}}
{{/* http://nginx.org/en/docs/http/ngx_http_log_module.html#access_log */}}
map $request $loggable {
{{ range $reqUri := $cfg.skipAccessLogUrls }}
{{ range $reqUri := $cfg.SkipAccessLogURLs }}
{{ $reqUri }} 0;{{ end }}
default 1;
}
access_log /var/log/nginx/access.log upstreaminfo if=$loggable;
error_log /var/log/nginx/error.log {{ $cfg.errorLogLevel }};
error_log /var/log/nginx/error.log {{ $cfg.ErrorLogLevel }};
{{ if not (empty .defResolver) }}# Custom dns resolver.
resolver {{ .defResolver }} valid=30s;
{{ if not (empty $cfg.Resolver) }}# Custom dns resolver.
resolver {{ $cfg.Resolver }} valid=30s;
resolver_timeout 10s;
{{ end }}
@ -98,14 +98,14 @@ http {
{{/* normal nginx behavior we have to use this approach. */}}
# Retain the default nginx handling of requests without a "Connection" header
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
default upgrade;
'' close;
}
# trust http_x_forwarded_proto headers correctly indicate ssl offloading
map $http_x_forwarded_proto $pass_access_scheme {
default $http_x_forwarded_proto;
'' $scheme;
default $http_x_forwarded_proto;
'' $scheme;
}
# Map a response error watching the header Content-Type
@ -124,51 +124,51 @@ http {
}
server_name_in_redirect off;
port_in_redirect off;
port_in_redirect off;
ssl_protocols {{ $cfg.sslProtocols }};
ssl_protocols {{ $cfg.SSLProtocols }};
# turn on session caching to drastically improve performance
{{ if $cfg.sslSessionCache }}
ssl_session_cache builtin:1000 shared:SSL:{{ $cfg.sslSessionCacheSize }};
ssl_session_timeout {{ $cfg.sslSessionTimeout }};
{{ if $cfg.SSLSessionCache }}
ssl_session_cache builtin:1000 shared:SSL:{{ $cfg.SSLSessionCacheSize }};
ssl_session_timeout {{ $cfg.SSLSessionTimeout }};
{{ end }}
# allow configuring ssl session tickets
ssl_session_tickets {{ if $cfg.sslSessionTickets }}on{{ else }}off{{ end }};
ssl_session_tickets {{ if $cfg.SSLSessionTickets }}on{{ else }}off{{ end }};
# slightly reduce the time-to-first-byte
ssl_buffer_size {{ $cfg.sslBufferSize }};
ssl_buffer_size {{ $cfg.SSLBufferSize }};
{{ if not (empty $cfg.sslCiphers) }}
{{ if not (empty $cfg.SSLCiphers) }}
# allow configuring custom ssl ciphers
ssl_ciphers '{{ $cfg.sslCiphers }}';
ssl_ciphers '{{ $cfg.SSLCiphers }}';
ssl_prefer_server_ciphers on;
{{ end }}
{{ if not (empty .sslDHParam) }}
{{ if not (empty $cfg.SSLDHParam) }}
# allow custom DH file http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_dhparam
ssl_dhparam {{ .sslDHParam }};
ssl_dhparam {{ $cfg.SSLDHParam }};
{{ end }}
{{ if not $cfg.enableDynamicTlsRecords }}
{{ if not $cfg.EnableDynamicTLSRecords }}
ssl_dyn_rec_size_lo 0;
{{ end }}
{{ if .customErrors }}
{{ if .CustomErrors }}
# Custom error pages
proxy_intercept_errors on;
{{ end }}
{{ range $errCode := $cfg.customHttpErrors }}
{{ range $errCode := $cfg.CustomHTTPErrors }}
error_page {{ $errCode }} = @custom_{{ $errCode }};{{ end }}
# In case of errors try the next upstream server before returning an error
proxy_next_upstream error timeout invalid_header http_502 http_503 http_504{{ if $cfg.retryNonIdempotent }} non_idempotent{{ end }};
proxy_next_upstream error timeout invalid_header http_502 http_503 http_504{{ if $cfg.RetryNonIdempotent }} non_idempotent{{ end }};
{{range $name, $upstream := .upstreams}}
{{range $name, $upstream := $backends}}
upstream {{$upstream.Name}} {
{{ if $cfg.enableStickySessions }}
{{ if $cfg.EnableStickySessions }}
sticky hash=sha1 httponly;
{{ else }}
least_conn;
@ -180,26 +180,26 @@ http {
{{/* build all the required rate limit zones. Each annotation requires a dedicated zone */}}
{{/* 1MB -> 16 thousand 64-byte states or about 8 thousand 128-byte states */}}
{{ range $zone := (buildRateLimitZones .servers) }}
{{ range $zone := (buildRateLimitZones .Servers) }}
{{ $zone }}
{{ end }}
{{ range $server := .servers }}
{{ range $server := .Servers }}
server {
server_name {{ $server.Name }};
listen 80{{ if $cfg.useProxyProtocol }} proxy_protocol{{ end }};
{{ if $server.SSL }}listen 442 {{ if $cfg.useProxyProtocol }}proxy_protocol{{ end }} ssl {{ if $cfg.useHttp2 }}http2{{ end }};
server_name {{ $server.Hostname }};
listen 80{{ if $cfg.UseProxyProtocol }} proxy_protocol{{ end }};
{{ if not (empty $server.SSLCertificate) }}listen 442 {{ if $cfg.UseProxyProtocol }}proxy_protocol{{ end }} ssl {{ if $cfg.UseHttp2 }}http2{{ end }};
{{/* comment PEM sha is required to detect changes in the generated configuration and force a reload */}}
# PEM sha: {{ $server.SSLPemChecksum }}
ssl_certificate {{ $server.SSLCertificate }};
ssl_certificate_key {{ $server.SSLCertificate }};
{{ end }}
{{ if (and $server.SSL $cfg.hsts) }}
more_set_headers "Strict-Transport-Security: max-age={{ $cfg.hstsMaxAge }}{{ if $cfg.hstsIncludeSubdomains }}; includeSubDomains{{ end }}; preload";
{{ if (and (not (empty $server.SSLCertificate)) $cfg.HSTS) }}
more_set_headers "Strict-Transport-Security: max-age={{ $cfg.HSTSMaxAge }}{{ if $cfg.HSTSIncludeSubdomains }}; includeSubDomains{{ end }}; preload";
{{ end }}
{{ if $cfg.enableVtsStatus }}vhost_traffic_status_filter_by_set_key $geoip_country_code country::$server_name;{{ end }}
{{ if $cfg.EnableVtsStatus }}vhost_traffic_status_filter_by_set_key $geoip_country_code country::$server_name;{{ end }}
{{ range $location := $server.Locations }}
{{ $path := buildLocation $location }}
@ -240,7 +240,7 @@ http {
auth_request {{ $authPath }};
{{ end }}
{{ if (and $server.SSL $location.Redirect.SSLRedirect) }}
{{ if (and (not (empty $server.SSLCertificate)) $location.Redirect.SSLRedirect) }}
# enforce ssl on server side
if ($scheme = http) {
return 301 https://$host$request_uri;
@ -256,7 +256,6 @@ http {
auth_basic "{{ $location.BasicDigestAuth.Realm }}";
auth_basic_user_file {{ $location.BasicDigestAuth.File }};
{{ else }}
#TODO: add nginx-http-auth-digest module
auth_digest "{{ $location.BasicDigestAuth.Realm }}";
auth_digest_user_file {{ $location.BasicDigestAuth.File }};
{{ end }}
@ -300,14 +299,14 @@ http {
proxy_set_header Accept-Encoding "";
{{ end }}
set $proxy_upstream_name "{{ $location.Backend.Name }}";
{{ buildProxyPass $location }}
set $proxy_upstream_name "{{ $location.Backend }}";
{{ buildProxyPass $backends $location }}
}
{{ end }}
{{ if eq $server.Name "_" }}
{{ if eq $server.Hostname "_" }}
# health checks in cloud providers require the use of port 80
location {{ $healthzURL }} {
location {{ $healthzURI }} {
access_log off;
return 200;
}
@ -322,6 +321,7 @@ http {
stub_status on;
}
{{ end }}
{{ template "CUSTOM_ERRORS" $cfg }}
}
@ -332,15 +332,15 @@ http {
# Use the port 18080 (random value just to avoid known ports) as default port for nginx.
# Changing this value requires a change in:
# https://github.com/kubernetes/contrib/blob/master/ingress/controllers/nginx/nginx/command.go#L104
listen 18080 default_server reuseport backlog={{ .backlogSize }};
listen 18080 default_server reuseport backlog={{ .BacklogSize }};
location {{ $healthzURL }} {
location {{ $healthzURI }} {
access_log off;
return 200;
}
location /nginx_status {
{{ if $cfg.enableVtsStatus }}
{{ if $cfg.EnableVtsStatus }}
vhost_traffic_status_display;
vhost_traffic_status_display_format html;
{{ else }}
@ -362,7 +362,7 @@ http {
set $proxy_upstream_name "-";
location / {
{{ if .customErrors }}
{{ if .CustomErrors }}
content_by_lua_block {
openURL(503)
}
@ -376,15 +376,14 @@ http {
stream {
# map FQDN that requires SSL passthrough
map $ssl_preread_server_name $stream_upstream {
{{ range $i, $passthrough := .passthroughUpstreams }}
{{ $passthrough.Host }} {{ $passthrough.Upstream.Name }}-{{ $i }}-pt;
{{ range $i, $passthrough := .PassthrougBackends }}
{{ $passthrough.Hostname }} {{ $passthrough.Backend }};
{{ end }}
# send SSL traffic to this nginx in a different port
default nginx-ssl-backend;
}
log_format log_stream '$remote_addr [$time_local] $protocol [$ssl_preread_server_name] [$stream_upstream] '
'$status $bytes_sent $bytes_received $session_time';
log_format log_stream '$remote_addr [$time_local] $protocol [$ssl_preread_server_name] [$stream_upstream] $status $bytes_sent $bytes_received $session_time';
access_log /var/log/nginx/access.log log_stream;
error_log /var/log/nginx/error.log;
@ -394,56 +393,20 @@ stream {
server 127.0.0.1:442;
}
{{ range $i, $passthrough := .passthroughUpstreams }}
upstream {{ $passthrough.Name }}-{{ $i }}-pt {
{{ range $server := $passthrough.Endpoints }}server {{ $server.Address }}:{{ $server.Port }};
{{ end }}
}
{{ end }}
{{ buildSSPassthroughUpstreams $backends .PassthrougBackends }}
server {
listen 443;
{{ if $cfg.useProxyProtocol }}proxy_protocol on;{{ end }}
{{ if $cfg.UseProxyProtocol }}proxy_protocol on;{{ end }}
proxy_pass $stream_upstream;
ssl_preread on;
}
# TCP services
{{ range $i, $tcpServer := .tcpUpstreams }}
upstream tcp-{{ $tcpServer.Upstream.Name }} {
{{ range $server := $tcpServer.Upstream.Endpoints }}server {{ $server.Address }}:{{ $server.Port }};
{{ end }}
}
server {
listen {{ $tcpServer.Path }};
proxy_connect_timeout {{ $tcpServer.Proxy.ConnectTimeout }}s;
proxy_timeout {{ $tcpServer.Proxy.ReadTimeout }}s;
proxy_pass tcp-{{ $tcpServer.Upstream.Name }};
}
{{ end }}
# UDP services
{{ range $i, $udpServer := .udpUpstreams }}
upstream udp-{{ $udpServer.Upstream.Name }} {
{{ range $server := $udpServer.Upstream.Endpoints }}server {{ $server.Address }}:{{ $server.Port }};
{{ end }}
}
server {
listen {{ $udpServer.Path }} udp;
proxy_timeout 10s;
proxy_responses 1;
proxy_pass udp-{{ $udpServer.Upstream.Name }};
}
{{ end }}
}
{{/* definition of templates to avoid repetitions */}}
{{ define "CUSTOM_ERRORS" }}
{{ range $errCode := .customHttpErrors }}
{{ range $errCode := .CustomHTTPErrors }}
location @custom_{{ $errCode }} {
internal;
content_by_lua_block {

File diff suppressed because it is too large Load diff