Live Nginx (re)configuration without reloading (#2174)

This commit is contained in:
Elvin Efendi 2018-03-18 09:13:41 -04:00 committed by Manuel Alejandro de Brito Fontes
parent 41cefeb178
commit c90a4e811e
13 changed files with 759 additions and 114 deletions

View file

@ -307,7 +307,7 @@ func buildLoadBalancingConfig(b interface{}, fallbackLoadBalancing string) strin
// (specified through the nginx.ingress.kubernetes.io/rewrite-to annotation)
// If the annotation nginx.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(host string, b interface{}, loc interface{}) string {
func buildProxyPass(host string, b interface{}, loc interface{}, dynamicConfigurationEnabled bool) string {
backends, ok := b.([]*ingress.Backend)
if !ok {
glog.Errorf("expected an '[]*ingress.Backend' type but %T was returned", b)
@ -323,14 +323,19 @@ func buildProxyPass(host string, b interface{}, loc interface{}) string {
path := location.Path
proto := "http"
upstreamName := location.Backend
upstreamName := "upstream_balancer"
if !dynamicConfigurationEnabled {
upstreamName = location.Backend
}
for _, backend := range backends {
if backend.Name == location.Backend {
if backend.Secure || backend.SSLPassthrough {
proto = "https"
}
if isSticky(host, location, backend.SessionAffinity.CookieSessionAffinity.Locations) {
if !dynamicConfigurationEnabled && isSticky(host, location, backend.SessionAffinity.CookieSessionAffinity.Locations) {
upstreamName = fmt.Sprintf("sticky-%v", upstreamName)
}
@ -340,6 +345,7 @@ func buildProxyPass(host string, b interface{}, loc interface{}) string {
// defProxyPass returns the default proxy_pass, just the name of the upstream
defProxyPass := fmt.Sprintf("proxy_pass %s://%s;", proto, upstreamName)
// if the path in the ingress rule is equals to the target: no special rewrite
if path == location.Rewrite.Target {
return defProxyPass

View file

@ -37,72 +37,262 @@ import (
)
var (
// TODO: add tests for secure endpoints
// TODO: add tests for SSLPassthrough
tmplFuncTestcases = map[string]struct {
Path string
Target string
Location string
ProxyPass string
AddBaseURL bool
BaseURLScheme string
Sticky bool
XForwardedPrefix bool
Path string
Target string
Location string
ProxyPass string
AddBaseURL bool
BaseURLScheme string
Sticky bool
XForwardedPrefix bool
DynamicConfigurationEnabled bool
SecureBackend bool
}{
"invalid redirect / to /": {"/", "/", "/", "proxy_pass http://upstream-name;", false, "", false, false},
"redirect / to /jenkins": {"/", "/jenkins", "~* /",
"when secure backend enabled": {
"/",
"/",
"/",
"proxy_pass https://upstream-name;",
false,
"",
false,
false,
false,
true},
"when secure backend and stickeness enabled": {
"/",
"/",
"/",
"proxy_pass https://sticky-upstream-name;",
false,
"",
true,
false,
false,
true},
"when secure backend and dynamic config enabled": {
"/",
"/",
"/",
"proxy_pass https://upstream_balancer;",
false,
"",
false,
false,
true,
true},
"when secure backend, stickeness and dynamic config enabled": {
"/",
"/",
"/",
"proxy_pass https://upstream_balancer;",
false,
"",
true,
false,
true,
true},
"invalid redirect / to / with dynamic config enabled": {
"/",
"/",
"/",
"proxy_pass http://upstream_balancer;",
false,
"",
false,
false,
true,
false},
"invalid redirect / to /": {
"/",
"/",
"/",
"proxy_pass http://upstream-name;",
false,
"",
false,
false,
false,
false},
"redirect / to /jenkins": {
"/",
"/jenkins",
"~* /",
`
rewrite /(.*) /jenkins/$1 break;
proxy_pass http://upstream-name;
`, false, "", false, false},
"redirect /something to /": {"/something", "/", `~* ^/something\/?(?<baseuri>.*)`, `
`,
false,
"",
false,
false,
false,
false},
"redirect /something to /": {
"/something",
"/",
`~* ^/something\/?(?<baseuri>.*)`,
`
rewrite /something/(.*) /$1 break;
rewrite /something / break;
proxy_pass http://upstream-name;
`, false, "", false, false},
"redirect /end-with-slash/ to /not-root": {"/end-with-slash/", "/not-root", "~* ^/end-with-slash/(?<baseuri>.*)", `
`,
false,
"",
false,
false,
false,
false},
"redirect /end-with-slash/ to /not-root": {
"/end-with-slash/",
"/not-root",
"~* ^/end-with-slash/(?<baseuri>.*)",
`
rewrite /end-with-slash/(.*) /not-root/$1 break;
proxy_pass http://upstream-name;
`, false, "", false, false},
"redirect /something-complex to /not-root": {"/something-complex", "/not-root", `~* ^/something-complex\/?(?<baseuri>.*)`, `
`,
false,
"",
false,
false,
false,
false},
"redirect /something-complex to /not-root": {
"/something-complex",
"/not-root",
`~* ^/something-complex\/?(?<baseuri>.*)`,
`
rewrite /something-complex/(.*) /not-root/$1 break;
proxy_pass http://upstream-name;
`, false, "", false, false},
"redirect / to /jenkins and rewrite": {"/", "/jenkins", "~* /", `
`,
false,
"",
false,
false,
false,
false},
"redirect / to /jenkins and rewrite": {
"/",
"/jenkins",
"~* /",
`
rewrite /(.*) /jenkins/$1 break;
proxy_pass http://upstream-name;
subs_filter '(<(?:H|h)(?:E|e)(?:A|a)(?:D|d)(?:[^">]|"[^"]*")*>)' '$1<base href="$scheme://$http_host/$baseuri">' ro;
`, true, "", false, false},
"redirect /something to / and rewrite": {"/something", "/", `~* ^/something\/?(?<baseuri>.*)`, `
`,
true,
"",
false,
false,
false,
false},
"redirect /something to / and rewrite": {
"/something",
"/",
`~* ^/something\/?(?<baseuri>.*)`,
`
rewrite /something/(.*) /$1 break;
rewrite /something / break;
proxy_pass http://upstream-name;
subs_filter '(<(?:H|h)(?:E|e)(?:A|a)(?:D|d)(?:[^">]|"[^"]*")*>)' '$1<base href="$scheme://$http_host/something/$baseuri">' ro;
`, true, "", false, false},
"redirect /end-with-slash/ to /not-root and rewrite": {"/end-with-slash/", "/not-root", `~* ^/end-with-slash/(?<baseuri>.*)`, `
`,
true,
"",
false,
false,
false,
false},
"redirect /end-with-slash/ to /not-root and rewrite": {
"/end-with-slash/",
"/not-root",
`~* ^/end-with-slash/(?<baseuri>.*)`,
`
rewrite /end-with-slash/(.*) /not-root/$1 break;
proxy_pass http://upstream-name;
subs_filter '(<(?:H|h)(?:E|e)(?:A|a)(?:D|d)(?:[^">]|"[^"]*")*>)' '$1<base href="$scheme://$http_host/end-with-slash/$baseuri">' ro;
`, true, "", false, false},
"redirect /something-complex to /not-root and rewrite": {"/something-complex", "/not-root", `~* ^/something-complex\/?(?<baseuri>.*)`, `
`,
true,
"",
false,
false,
false,
false},
"redirect /something-complex to /not-root and rewrite": {
"/something-complex",
"/not-root",
`~* ^/something-complex\/?(?<baseuri>.*)`,
`
rewrite /something-complex/(.*) /not-root/$1 break;
proxy_pass http://upstream-name;
subs_filter '(<(?:H|h)(?:E|e)(?:A|a)(?:D|d)(?:[^">]|"[^"]*")*>)' '$1<base href="$scheme://$http_host/something-complex/$baseuri">' ro;
`, true, "", false, false},
"redirect /something to / and rewrite with specific scheme": {"/something", "/", `~* ^/something\/?(?<baseuri>.*)`, `
`,
true,
"",
false,
false,
false,
false},
"redirect /something to / and rewrite with specific scheme": {
"/something",
"/",
`~* ^/something\/?(?<baseuri>.*)`,
`
rewrite /something/(.*) /$1 break;
rewrite /something / break;
proxy_pass http://upstream-name;
subs_filter '(<(?:H|h)(?:E|e)(?:A|a)(?:D|d)(?:[^">]|"[^"]*")*>)' '$1<base href="http://$http_host/something/$baseuri">' ro;
`, true, "http", false, false},
"redirect / to /something with sticky enabled": {"/", "/something", `~* /`, `
`,
true,
"http",
false,
false,
false,
false},
"redirect / to /something with sticky enabled": {
"/",
"/something",
`~* /`,
`
rewrite /(.*) /something/$1 break;
proxy_pass http://sticky-upstream-name;
`, false, "http", true, false},
"add the X-Forwarded-Prefix header": {"/there", "/something", `~* ^/there\/?(?<baseuri>.*)`, `
`,
false,
"http",
true,
false,
false,
false},
"redirect / to /something with sticky and dynamic config enabled": {
"/",
"/something",
`~* /`,
`
rewrite /(.*) /something/$1 break;
proxy_pass http://upstream_balancer;
`,
false,
"http",
true,
false,
true,
false},
"add the X-Forwarded-Prefix header": {
"/there",
"/something",
`~* ^/there\/?(?<baseuri>.*)`,
`
rewrite /there/(.*) /something/$1 break;
proxy_set_header X-Forwarded-Prefix "/there/";
proxy_pass http://sticky-upstream-name;
`, false, "http", true, true},
`,
false,
"http",
true,
true,
false,
false},
}
)
@ -151,24 +341,25 @@ func TestBuildProxyPass(t *testing.T) {
XForwardedPrefix: tc.XForwardedPrefix,
}
backends := []*ingress.Backend{}
backend := &ingress.Backend{
Name: defaultBackend,
Secure: tc.SecureBackend,
}
if tc.Sticky {
backends = []*ingress.Backend{
{
Name: defaultBackend,
SessionAffinity: ingress.SessionAffinityConfig{
AffinityType: "cookie",
CookieSessionAffinity: ingress.CookieSessionAffinity{
Locations: map[string][]string{
defaultHost: {tc.Path},
},
},
backend.SessionAffinity = ingress.SessionAffinityConfig{
AffinityType: "cookie",
CookieSessionAffinity: ingress.CookieSessionAffinity{
Locations: map[string][]string{
defaultHost: {tc.Path},
},
},
}
}
pp := buildProxyPass(defaultHost, backends, loc)
backends := []*ingress.Backend{backend}
pp := buildProxyPass(defaultHost, backends, loc, tc.DynamicConfigurationEnabled)
if !strings.EqualFold(tc.ProxyPass, pp) {
t.Errorf("%s: expected \n'%v'\nbut returned \n'%v'", k, tc.ProxyPass, pp)
}