From 859b298d42b6e3a5d02535ddca0ac91e799b2e8b Mon Sep 17 00:00:00 2001 From: Manuel Alejandro de Brito Fontes Date: Mon, 8 Oct 2018 12:26:06 -0300 Subject: [PATCH] Remove annotations grpc-backend and secure-backend already deprecated --- docs/examples/grpc/README.md | 5 +- .../nginx-configuration/annotations.md | 28 ------- internal/ingress/annotations/annotations.go | 3 - .../ingress/annotations/annotations_test.go | 36 ++------- internal/ingress/annotations/grpc/main.go | 44 ---------- .../ingress/annotations/grpc/main_test.go | 80 ------------------- .../annotations/secureupstream/main.go | 8 +- .../annotations/secureupstream/main_test.go | 6 +- internal/ingress/controller/controller.go | 10 --- internal/ingress/controller/nginx.go | 1 - .../ingress/controller/template/template.go | 15 +--- .../controller/template/template_test.go | 68 +++++++++++----- internal/ingress/types.go | 8 -- internal/ingress/types_equals.go | 6 -- 14 files changed, 64 insertions(+), 254 deletions(-) delete mode 100644 internal/ingress/annotations/grpc/main.go delete mode 100644 internal/ingress/annotations/grpc/main_test.go diff --git a/docs/examples/grpc/README.md b/docs/examples/grpc/README.md index f2a6144bb..0416f5e07 100644 --- a/docs/examples/grpc/README.md +++ b/docs/examples/grpc/README.md @@ -48,8 +48,7 @@ inside the cluster and arrive "insecure"). For your own application you may or may not want to do this. If you prefer to forward encrypted traffic to your POD and terminate TLS at the gRPC server -itself, add the ingress annotation `nginx.ingress.kubernetes.io/secure-backends: -"true"`. +itself, add the ingress annotation `nginx.ingress.kubernetes.io/backend-protocol: "GRPCS"`. ### Step 2: the kubernetes `Service` @@ -69,7 +68,7 @@ $ kubectl create -f ingress.yaml A few things to note: 1. We've tagged the ingress with the annotation - `nginx.ingress.kubernetes.io/grpc-backend: "true"`. This is the magic + `nginx.ingress.kubernetes.io/backend-protocol: "GRPC"`. This is the magic ingredient that sets up the appropriate nginx configuration to route http/2 traffic to our service. 1. We're terminating TLS at the ingress and have configured an SSL certificate diff --git a/docs/user-guide/nginx-configuration/annotations.md b/docs/user-guide/nginx-configuration/annotations.md index b8f1c4a10..b1a771643 100644 --- a/docs/user-guide/nginx-configuration/annotations.md +++ b/docs/user-guide/nginx-configuration/annotations.md @@ -40,7 +40,6 @@ You can add these Kubernetes annotations to specific Ingress objects to customiz |[nginx.ingress.kubernetes.io/cors-max-age](#enable-cors)|number| |[nginx.ingress.kubernetes.io/force-ssl-redirect](#server-side-https-enforcement-through-redirect)|"true" or "false"| |[nginx.ingress.kubernetes.io/from-to-www-redirect](#redirect-from-to-www)|"true" or "false"| -|[nginx.ingress.kubernetes.io/grpc-backend](#grpc-backend)|"true" or "false"| |[nginx.ingress.kubernetes.io/limit-connections](#rate-limiting)|number| |[nginx.ingress.kubernetes.io/limit-rps](#rate-limiting)|number| |[nginx.ingress.kubernetes.io/permanent-redirect](#permanent-redirect)|string| @@ -58,7 +57,6 @@ You can add these Kubernetes annotations to specific Ingress objects to customiz |[nginx.ingress.kubernetes.io/proxy-redirect-to](#proxy-redirect)|string| |[nginx.ingress.kubernetes.io/enable-rewrite-log](#enable-rewrite-log)|"true" or "false"| |[nginx.ingress.kubernetes.io/rewrite-target](#rewrite)|URI| -|[nginx.ingress.kubernetes.io/secure-backends](#secure-backends)|"true" or "false"| |[nginx.ingress.kubernetes.io/secure-verify-ca-secret](#secure-backends)|string| |[nginx.ingress.kubernetes.io/server-alias](#server-alias)|string| |[nginx.ingress.kubernetes.io/server-snippet](#server-snippet)|string| @@ -393,19 +391,6 @@ the User guide. Because SSL Passthrough works on layer 4 of the OSI model (TCP) and not on the layer 7 (HTTP), using SSL Passthrough invalidates all the other annotations set on an Ingress object. -### Secure backends DEPRECATED (since 0.18.0) - -Please use `nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"` - -By default NGINX uses plain HTTP to reach the services. -Adding the annotation `nginx.ingress.kubernetes.io/secure-backends: "true"` in the Ingress rule changes the protocol to HTTPS. -If you want to validate the upstream against a specific certificate, you can create a secret with it and reference the secret with the annotation `nginx.ingress.kubernetes.io/secure-verify-ca-secret`. - -!!! attention - - Note that if an invalid or non-existent secret is given, - the ingress controller will ignore the `secure-backends` annotation. - ### Service Upstream By default the NGINX ingress controller uses a list of all endpoints (Pod IP/port) in the NGINX upstream configuration. @@ -588,19 +573,6 @@ nginx.ingress.kubernetes.io/lua-resty-waf-extra-rules: '[=[ { "access": [ { "act For details on how to write WAF rules, please refer to [https://github.com/p0pr0ck5/lua-resty-waf](https://github.com/p0pr0ck5/lua-resty-waf). -### gRPC backend DEPRECATED (since 0.18.0) - -Please use `nginx.ingress.kubernetes.io/backend-protocol: "GRPC"` or `nginx.ingress.kubernetes.io/backend-protocol: "GRPCS"` - -Since NGINX 1.13.10 it is possible to expose [gRPC services natively](http://nginx.org/en/docs/http/ngx_http_grpc_module.html) - -You only need to add the annotation `nginx.ingress.kubernetes.io/grpc-backend: "true"` to enable this feature. -Additionally, if the gRPC service requires TLS, add `nginx.ingress.kubernetes.io/secure-backends: "true"`. - -!!! attention - This feature requires HTTP2 to work which means we need to expose this service using HTTPS. - Exposing a gRPC service using HTTP is not supported. - [configmap]: ./configmap.md ### InfluxDB diff --git a/internal/ingress/annotations/annotations.go b/internal/ingress/annotations/annotations.go index 34c8a91b8..d137c52c3 100644 --- a/internal/ingress/annotations/annotations.go +++ b/internal/ingress/annotations/annotations.go @@ -34,7 +34,6 @@ import ( "k8s.io/ingress-nginx/internal/ingress/annotations/connection" "k8s.io/ingress-nginx/internal/ingress/annotations/cors" "k8s.io/ingress-nginx/internal/ingress/annotations/defaultbackend" - "k8s.io/ingress-nginx/internal/ingress/annotations/grpc" "k8s.io/ingress-nginx/internal/ingress/annotations/healthcheck" "k8s.io/ingress-nginx/internal/ingress/annotations/influxdb" "k8s.io/ingress-nginx/internal/ingress/annotations/ipwhitelist" @@ -95,7 +94,6 @@ type Ingress struct { XForwardedPrefix bool SSLCiphers string Logs log.Config - GRPC bool LuaRestyWAF luarestywaf.Config InfluxDB influxdb.Config } @@ -136,7 +134,6 @@ func NewAnnotationExtractor(cfg resolver.Resolver) Extractor { "XForwardedPrefix": xforwardedprefix.NewParser(cfg), "SSLCiphers": sslcipher.NewParser(cfg), "Logs": log.NewParser(cfg), - "GRPC": grpc.NewParser(cfg), "LuaRestyWAF": luarestywaf.NewParser(cfg), "InfluxDB": influxdb.NewParser(cfg), "BackendProtocol": backendprotocol.NewParser(cfg), diff --git a/internal/ingress/annotations/annotations_test.go b/internal/ingress/annotations/annotations_test.go index 729499836..6d7947c99 100644 --- a/internal/ingress/annotations/annotations_test.go +++ b/internal/ingress/annotations/annotations_test.go @@ -30,7 +30,6 @@ import ( ) var ( - annotationSecureUpstream = parser.GetAnnotationWithPrefix("secure-backends") annotationSecureVerifyCACert = parser.GetAnnotationWithPrefix("secure-verify-ca-secret") annotationUpsMaxFails = parser.GetAnnotationWithPrefix("upstream-max-fails") annotationUpsFailTimeout = parser.GetAnnotationWithPrefix("upstream-fail-timeout") @@ -40,6 +39,7 @@ var ( annotationCorsAllowMethods = parser.GetAnnotationWithPrefix("cors-allow-methods") annotationCorsAllowHeaders = parser.GetAnnotationWithPrefix("cors-allow-headers") annotationCorsAllowCredentials = parser.GetAnnotationWithPrefix("cors-allow-credentials") + backendProtocol = parser.GetAnnotationWithPrefix("backend-protocol") defaultCorsMethods = "GET, PUT, POST, DELETE, PATCH, OPTIONS" defaultCorsHeaders = "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization" annotationAffinityCookieName = parser.GetAnnotationWithPrefix("session-cookie-name") @@ -111,30 +111,6 @@ func buildIngress() *extensions.Ingress { } } -func TestSecureUpstream(t *testing.T) { - ec := NewAnnotationExtractor(mockCfg{}) - ing := buildIngress() - - fooAnns := []struct { - annotations map[string]string - er bool - }{ - {map[string]string{annotationSecureUpstream: "true"}, true}, - {map[string]string{annotationSecureUpstream: "false"}, false}, - {map[string]string{annotationSecureUpstream + "_no": "true"}, false}, - {map[string]string{}, false}, - {nil, false}, - } - - for _, foo := range fooAnns { - ing.SetAnnotations(foo.annotations) - r := ec.Extract(ing).SecureUpstream - if r.Secure != foo.er { - t.Errorf("Returned %v but expected %v", r, foo.er) - } - } -} - func TestSecureVerifyCACert(t *testing.T) { ec := NewAnnotationExtractor(mockCfg{ MockSecrets: map[string]*apiv1.Secret{ @@ -151,11 +127,11 @@ func TestSecureVerifyCACert(t *testing.T) { annotations map[string]string exists bool }{ - {1, map[string]string{annotationSecureUpstream: "true", annotationSecureVerifyCACert: "not"}, false}, - {2, map[string]string{annotationSecureUpstream: "false", annotationSecureVerifyCACert: "secure-verify-ca"}, false}, - {3, map[string]string{annotationSecureUpstream: "true", annotationSecureVerifyCACert: "secure-verify-ca"}, true}, - {4, map[string]string{annotationSecureUpstream: "true", annotationSecureVerifyCACert + "_not": "secure-verify-ca"}, false}, - {5, map[string]string{annotationSecureUpstream: "true"}, false}, + {1, map[string]string{backendProtocol: "HTTPS", annotationSecureVerifyCACert: "not"}, false}, + {2, map[string]string{backendProtocol: "HTTP", annotationSecureVerifyCACert: "secure-verify-ca"}, false}, + {3, map[string]string{backendProtocol: "HTTPS", annotationSecureVerifyCACert: "secure-verify-ca"}, true}, + {4, map[string]string{backendProtocol: "HTTPS", annotationSecureVerifyCACert + "_not": "secure-verify-ca"}, false}, + {5, map[string]string{backendProtocol: "HTTPS"}, false}, {6, map[string]string{}, false}, {7, nil, false}, } diff --git a/internal/ingress/annotations/grpc/main.go b/internal/ingress/annotations/grpc/main.go deleted file mode 100644 index 98036ee6a..000000000 --- a/internal/ingress/annotations/grpc/main.go +++ /dev/null @@ -1,44 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package grpc - -import ( - extensions "k8s.io/api/extensions/v1beta1" - - "k8s.io/ingress-nginx/internal/ingress/annotations/parser" - ing_errors "k8s.io/ingress-nginx/internal/ingress/errors" - "k8s.io/ingress-nginx/internal/ingress/resolver" -) - -type grpc struct { - r resolver.Resolver -} - -// NewParser creates a new gRPC annotation parser -func NewParser(r resolver.Resolver) parser.IngressAnnotation { - return grpc{r} -} - -// ParseAnnotations parses the annotations contained in the ingress -// rule used to indicate if the Kubernetes service exposes gRPC -func (a grpc) Parse(ing *extensions.Ingress) (interface{}, error) { - if ing.GetAnnotations() == nil { - return false, ing_errors.ErrMissingAnnotations - } - - return parser.GetBoolAnnotation("grpc-backend", ing) -} diff --git a/internal/ingress/annotations/grpc/main_test.go b/internal/ingress/annotations/grpc/main_test.go deleted file mode 100644 index fccc1138c..000000000 --- a/internal/ingress/annotations/grpc/main_test.go +++ /dev/null @@ -1,80 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package grpc - -import ( - "testing" - - api "k8s.io/api/core/v1" - extensions "k8s.io/api/extensions/v1beta1" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/ingress-nginx/internal/ingress/annotations/parser" - "k8s.io/ingress-nginx/internal/ingress/resolver" - - "k8s.io/apimachinery/pkg/util/intstr" -) - -func buildIngress() *extensions.Ingress { - return &extensions.Ingress{ - ObjectMeta: meta_v1.ObjectMeta{ - Name: "foo", - Namespace: api.NamespaceDefault, - }, - Spec: extensions.IngressSpec{ - Backend: &extensions.IngressBackend{ - ServiceName: "default-backend", - ServicePort: intstr.FromInt(80), - }, - }, - } -} - -func TestParseAnnotations(t *testing.T) { - ing := buildIngress() - - _, err := NewParser(&resolver.Mock{}).Parse(ing) - if err == nil { - t.Errorf("unexpected error: %v", err) - } - - data := map[string]string{} - data[parser.GetAnnotationWithPrefix("grpc-backend")] = "true" - ing.SetAnnotations(data) - // test ingress using the annotation without a TLS section - _, err = NewParser(&resolver.Mock{}).Parse(ing) - if err != nil { - t.Errorf("unexpected error parsing ingress with sslpassthrough") - } - - // test with a valid host - ing.Spec.TLS = []extensions.IngressTLS{ - { - Hosts: []string{"foo.bar.com"}, - }, - } - i, err := NewParser(&resolver.Mock{}).Parse(ing) - if err != nil { - t.Errorf("expected error parsing ingress with sslpassthrough") - } - val, ok := i.(bool) - if !ok { - t.Errorf("expected a bool type") - } - if !val { - t.Errorf("expected true but false returned") - } -} diff --git a/internal/ingress/annotations/secureupstream/main.go b/internal/ingress/annotations/secureupstream/main.go index e973dacbc..f1f97a953 100644 --- a/internal/ingress/annotations/secureupstream/main.go +++ b/internal/ingress/annotations/secureupstream/main.go @@ -28,7 +28,6 @@ import ( // Config describes SSL backend configuration type Config struct { - Secure bool `json:"secure"` CACert resolver.AuthSSLCert `json:"caCert"` } @@ -44,13 +43,13 @@ func NewParser(r resolver.Resolver) parser.IngressAnnotation { // Parse parses the annotations contained in the ingress // rule used to indicate if the upstream servers should use SSL func (a su) Parse(ing *extensions.Ingress) (interface{}, error) { - s, _ := parser.GetBoolAnnotation("secure-backends", ing) + bp, _ := parser.GetStringAnnotation("backend-protocol", ing) ca, _ := parser.GetStringAnnotation("secure-verify-ca-secret", ing) secure := &Config{ - Secure: s, CACert: resolver.AuthSSLCert{}, } - if !s && ca != "" { + + if (bp != "HTTPS" && bp != "GRPCS") && ca != "" { return secure, errors.Errorf("trying to use CA from secret %v/%v on a non secure backend", ing.Namespace, ca) } @@ -65,7 +64,6 @@ func (a su) Parse(ing *extensions.Ingress) (interface{}, error) { return secure, nil } return &Config{ - Secure: s, CACert: *caCert, }, nil } diff --git a/internal/ingress/annotations/secureupstream/main_test.go b/internal/ingress/annotations/secureupstream/main_test.go index 13a7c4e2c..adee3c63a 100644 --- a/internal/ingress/annotations/secureupstream/main_test.go +++ b/internal/ingress/annotations/secureupstream/main_test.go @@ -79,7 +79,7 @@ func (cfg mockCfg) GetAuthCertificate(secret string) (*resolver.AuthSSLCert, err func TestAnnotations(t *testing.T) { ing := buildIngress() data := map[string]string{} - data[parser.GetAnnotationWithPrefix("secure-backends")] = "true" + data[parser.GetAnnotationWithPrefix("backend-protocol")] = "HTTPS" data[parser.GetAnnotationWithPrefix("secure-verify-ca-secret")] = "secure-verify-ca" ing.SetAnnotations(data) @@ -96,7 +96,7 @@ func TestAnnotations(t *testing.T) { func TestSecretNotFound(t *testing.T) { ing := buildIngress() data := map[string]string{} - data[parser.GetAnnotationWithPrefix("secure-backends")] = "true" + data[parser.GetAnnotationWithPrefix("backend-protocol")] = "HTTPS" data[parser.GetAnnotationWithPrefix("secure-verify-ca-secret")] = "secure-verify-ca" ing.SetAnnotations(data) _, err := NewParser(mockCfg{}).Parse(ing) @@ -108,7 +108,7 @@ func TestSecretNotFound(t *testing.T) { func TestSecretOnNonSecure(t *testing.T) { ing := buildIngress() data := map[string]string{} - data[parser.GetAnnotationWithPrefix("secure-backends")] = "false" + data[parser.GetAnnotationWithPrefix("backend-protocol")] = "HTTP" data[parser.GetAnnotationWithPrefix("secure-verify-ca-secret")] = "secure-verify-ca" ing.SetAnnotations(data) _, err := NewParser(mockCfg{ diff --git a/internal/ingress/controller/controller.go b/internal/ingress/controller/controller.go index d9afb87b9..88d32b611 100644 --- a/internal/ingress/controller/controller.go +++ b/internal/ingress/controller/controller.go @@ -348,7 +348,6 @@ func (n *NGINXController) getBackendServers(ingresses []*extensions.Ingress) ([] loc.UsePortInRedirects = anns.UsePortInRedirects loc.Connection = anns.Connection loc.Logs = anns.Logs - loc.GRPC = anns.GRPC loc.LuaRestyWAF = anns.LuaRestyWAF loc.InfluxDB = anns.InfluxDB loc.DefaultBackend = anns.DefaultBackend @@ -389,7 +388,6 @@ func (n *NGINXController) getBackendServers(ingresses []*extensions.Ingress) ([] UsePortInRedirects: anns.UsePortInRedirects, Connection: anns.Connection, Logs: anns.Logs, - GRPC: anns.GRPC, LuaRestyWAF: anns.LuaRestyWAF, InfluxDB: anns.InfluxDB, DefaultBackend: anns.DefaultBackend, @@ -523,9 +521,6 @@ func (n *NGINXController) createUpstreams(data []*extensions.Ingress, du *ingres glog.V(3).Infof("Creating upstream %q", defBackend) upstreams[defBackend] = newUpstream(defBackend) - if !upstreams[defBackend].Secure { - upstreams[defBackend].Secure = anns.SecureUpstream.Secure - } if upstreams[defBackend].SecureCACert.Secret == "" { upstreams[defBackend].SecureCACert = anns.SecureUpstream.CACert } @@ -577,10 +572,6 @@ func (n *NGINXController) createUpstreams(data []*extensions.Ingress, du *ingres upstreams[name] = newUpstream(name) upstreams[name].Port = path.Backend.ServicePort - if !upstreams[name].Secure { - upstreams[name].Secure = anns.SecureUpstream.Secure - } - if upstreams[name].SecureCACert.Secret == "" { upstreams[name].SecureCACert = anns.SecureUpstream.CACert } @@ -835,7 +826,6 @@ func (n *NGINXController) createServers(data []*extensions.Ingress, defLoc.UpstreamVhost = anns.UpstreamVhost defLoc.Whitelist = anns.Whitelist defLoc.Denied = anns.Denied - defLoc.GRPC = anns.GRPC defLoc.LuaRestyWAF = anns.LuaRestyWAF defLoc.InfluxDB = anns.InfluxDB } else { diff --git a/internal/ingress/controller/nginx.go b/internal/ingress/controller/nginx.go index aa4ccf86a..4af606214 100644 --- a/internal/ingress/controller/nginx.go +++ b/internal/ingress/controller/nginx.go @@ -763,7 +763,6 @@ func configureDynamically(pcfg *ingress.Configuration, port int, isDynamicCertif luaBackend := &ingress.Backend{ Name: backend.Name, Port: backend.Port, - Secure: backend.Secure, SSLPassthrough: backend.SSLPassthrough, SessionAffinity: backend.SessionAffinity, UpstreamHashBy: backend.UpstreamHashBy, diff --git a/internal/ingress/controller/template/template.go b/internal/ingress/controller/template/template.go index 2d5e5522c..501355492 100644 --- a/internal/ingress/controller/template/template.go +++ b/internal/ingress/controller/template/template.go @@ -456,12 +456,6 @@ func buildProxyPass(host string, b interface{}, loc interface{}, dynamicConfigur proxyPass = "ajp_pass" } - // TODO: Remove after the deprecation of grpc-backend annotation - if location.GRPC { - proxyPass = "grpc_pass" - proto = "grpc://" - } - upstreamName := "upstream_balancer" if !dynamicConfigurationEnabled { @@ -470,11 +464,10 @@ func buildProxyPass(host string, b interface{}, loc interface{}, dynamicConfigur for _, backend := range backends { if backend.Name == location.Backend { - if backend.Secure || backend.SSLPassthrough { - // TODO: Remove after the deprecation of secure-backend annotation + if backend.SSLPassthrough { proto = "https://" - // TODO: Remove after the deprecation of grpc-backend annotation - if location.GRPC { + + if location.BackendProtocol == "GRPCS" { proto = "grpcs://" } } @@ -974,7 +967,7 @@ func proxySetHeader(loc interface{}) string { return "proxy_set_header" } - if location.GRPC || location.BackendProtocol == "GRPC" || location.BackendProtocol == "GRPCS" { + if location.BackendProtocol == "GRPC" || location.BackendProtocol == "GRPCS" { return "grpc_set_header" } diff --git a/internal/ingress/controller/template/template_test.go b/internal/ingress/controller/template/template_test.go index d8622e2f6..5de8657d1 100644 --- a/internal/ingress/controller/template/template_test.go +++ b/internal/ingress/controller/template/template_test.go @@ -63,7 +63,8 @@ var ( false, false, true, - false}, + false, + }, "when secure backend and stickeness enabled": { "/", "/", @@ -75,7 +76,8 @@ var ( false, false, true, - false}, + false, + }, "when secure backend and dynamic config enabled": { "/", "/", @@ -99,7 +101,8 @@ var ( false, true, true, - false}, + false, + }, "invalid redirect / to / with dynamic config enabled": { "/", "/", @@ -111,7 +114,8 @@ var ( false, true, false, - false}, + false, + }, "invalid redirect / to /": { "/", "/", @@ -123,7 +127,8 @@ var ( false, false, false, - false}, + false, + }, "redirect / to /jenkins": { "/", "/jenkins", @@ -139,7 +144,8 @@ proxy_pass http://upstream-name; false, false, false, - true}, + true, + }, "redirect /something to /": { "/something", "/", @@ -155,7 +161,8 @@ proxy_pass http://upstream-name; false, false, false, - true}, + true, + }, "redirect /end-with-slash/ to /not-root": { "/end-with-slash/", "/not-root", @@ -171,7 +178,8 @@ proxy_pass http://upstream-name; false, false, false, - true}, + true, + }, "redirect /something-complex to /not-root": { "/something-complex", "/not-root", @@ -187,7 +195,8 @@ proxy_pass http://upstream-name; false, false, false, - true}, + true, + }, "redirect / to /jenkins and rewrite": { "/", "/jenkins", @@ -206,7 +215,8 @@ subs_filter '(<(?:H|h)(?:E|e)(?:A|a)(?:D|d)(?:[^">]|"[^"]*")*>)' '$1]|"[^"]*")*>)' '$1]|"[^"]*")*>)' '$1]|"[^"]*")*>)' '$1]|"[^"]*")*>)' '$1