Refactor handling of path Prefix and Exact
This commit is contained in:
parent
52726abaee
commit
3f153add00
10 changed files with 316 additions and 71 deletions
|
|
@ -430,6 +430,20 @@ func (n *NGINXController) getConfiguration(ingresses []*ingress.Ingress) (sets.S
|
|||
hosts := sets.NewString()
|
||||
|
||||
for _, server := range servers {
|
||||
// If a location is defined by a prefix string that ends with the slash character, and requests are processed by one of
|
||||
// proxy_pass, fastcgi_pass, uwsgi_pass, scgi_pass, memcached_pass, or grpc_pass, then the special processing is performed.
|
||||
// In response to a request with URI equal to // this string, but without the trailing slash, a permanent redirect with the
|
||||
// code 301 will be returned to the requested URI with the slash appended. If this is not desired, an exact match of the
|
||||
// URIand location could be defined like this:
|
||||
//
|
||||
// location /user/ {
|
||||
// proxy_pass http://user.example.com;
|
||||
// }
|
||||
// location = /user {
|
||||
// proxy_pass http://login.example.com;
|
||||
// }
|
||||
server.Locations = updateServerLocations(server.Locations)
|
||||
|
||||
if !hosts.Has(server.Hostname) {
|
||||
hosts.Insert(server.Hostname)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -270,8 +270,6 @@ func TestCheckIngress(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
var pathPrefix = networking.PathTypePrefix
|
||||
|
||||
func TestMergeAlternativeBackends(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
ingress *ingress.Ingress
|
||||
|
|
@ -295,7 +293,7 @@ func TestMergeAlternativeBackends(t *testing.T) {
|
|||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: "/",
|
||||
PathType: &pathPrefix,
|
||||
PathType: &pathTypePrefix,
|
||||
Backend: networking.IngressBackend{
|
||||
ServiceName: "http-svc-canary",
|
||||
ServicePort: intstr.IntOrString{
|
||||
|
|
@ -331,7 +329,7 @@ func TestMergeAlternativeBackends(t *testing.T) {
|
|||
Locations: []*ingress.Location{
|
||||
{
|
||||
Path: "/",
|
||||
PathType: &pathPrefix,
|
||||
PathType: &pathTypePrefix,
|
||||
Backend: "example-http-svc-80",
|
||||
},
|
||||
},
|
||||
|
|
@ -357,7 +355,7 @@ func TestMergeAlternativeBackends(t *testing.T) {
|
|||
Locations: []*ingress.Location{
|
||||
{
|
||||
Path: "/",
|
||||
PathType: &pathPrefix,
|
||||
PathType: &pathTypePrefix,
|
||||
Backend: "example-http-svc-80",
|
||||
},
|
||||
},
|
||||
|
|
@ -379,7 +377,7 @@ func TestMergeAlternativeBackends(t *testing.T) {
|
|||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: "/",
|
||||
PathType: &pathPrefix,
|
||||
PathType: &pathTypePrefix,
|
||||
Backend: networking.IngressBackend{
|
||||
ServiceName: "foo-http-svc-canary",
|
||||
ServicePort: intstr.IntOrString{
|
||||
|
|
@ -399,7 +397,7 @@ func TestMergeAlternativeBackends(t *testing.T) {
|
|||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: "/",
|
||||
PathType: &pathPrefix,
|
||||
PathType: &pathTypePrefix,
|
||||
Backend: networking.IngressBackend{
|
||||
ServiceName: "http-svc-canary",
|
||||
ServicePort: intstr.IntOrString{
|
||||
|
|
@ -447,7 +445,7 @@ func TestMergeAlternativeBackends(t *testing.T) {
|
|||
Locations: []*ingress.Location{
|
||||
{
|
||||
Path: "/",
|
||||
PathType: &pathPrefix,
|
||||
PathType: &pathTypePrefix,
|
||||
Backend: "example-foo-http-svc-80",
|
||||
},
|
||||
},
|
||||
|
|
@ -457,7 +455,7 @@ func TestMergeAlternativeBackends(t *testing.T) {
|
|||
Locations: []*ingress.Location{
|
||||
{
|
||||
Path: "/",
|
||||
PathType: &pathPrefix,
|
||||
PathType: &pathTypePrefix,
|
||||
Backend: "example-http-svc-80",
|
||||
},
|
||||
},
|
||||
|
|
@ -495,7 +493,7 @@ func TestMergeAlternativeBackends(t *testing.T) {
|
|||
Locations: []*ingress.Location{
|
||||
{
|
||||
Path: "/",
|
||||
PathType: &pathPrefix,
|
||||
PathType: &pathTypePrefix,
|
||||
Backend: "example-http-svc-80",
|
||||
},
|
||||
},
|
||||
|
|
@ -517,7 +515,7 @@ func TestMergeAlternativeBackends(t *testing.T) {
|
|||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: "/",
|
||||
PathType: &pathPrefix,
|
||||
PathType: &pathTypePrefix,
|
||||
Backend: networking.IngressBackend{
|
||||
ServiceName: "http-svc-canary",
|
||||
ServicePort: intstr.IntOrString{
|
||||
|
|
@ -582,7 +580,7 @@ func TestMergeAlternativeBackends(t *testing.T) {
|
|||
Locations: []*ingress.Location{
|
||||
{
|
||||
Path: "/",
|
||||
PathType: &pathPrefix,
|
||||
PathType: &pathTypePrefix,
|
||||
Backend: "example-http-svc-80",
|
||||
},
|
||||
},
|
||||
|
|
@ -608,7 +606,7 @@ func TestMergeAlternativeBackends(t *testing.T) {
|
|||
Locations: []*ingress.Location{
|
||||
{
|
||||
Path: "/",
|
||||
PathType: &pathPrefix,
|
||||
PathType: &pathTypePrefix,
|
||||
Backend: "example-http-svc-80",
|
||||
},
|
||||
},
|
||||
|
|
@ -650,7 +648,7 @@ func TestMergeAlternativeBackends(t *testing.T) {
|
|||
Locations: []*ingress.Location{
|
||||
{
|
||||
Path: "/",
|
||||
PathType: &pathPrefix,
|
||||
PathType: &pathTypePrefix,
|
||||
Backend: "upstream-default-backend",
|
||||
},
|
||||
},
|
||||
|
|
@ -663,7 +661,7 @@ func TestMergeAlternativeBackends(t *testing.T) {
|
|||
Locations: []*ingress.Location{
|
||||
{
|
||||
Path: "/",
|
||||
PathType: &pathPrefix,
|
||||
PathType: &pathTypePrefix,
|
||||
Backend: "upstream-default-backend",
|
||||
},
|
||||
},
|
||||
|
|
@ -999,7 +997,7 @@ func TestGetBackendServers(t *testing.T) {
|
|||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: "/",
|
||||
PathType: &pathPrefix,
|
||||
PathType: &pathTypePrefix,
|
||||
Backend: networking.IngressBackend{
|
||||
ServiceName: "http-svc-canary",
|
||||
ServicePort: intstr.IntOrString{
|
||||
|
|
@ -1059,7 +1057,7 @@ func TestGetBackendServers(t *testing.T) {
|
|||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: "/",
|
||||
PathType: &pathPrefix,
|
||||
PathType: &pathTypePrefix,
|
||||
Backend: networking.IngressBackend{
|
||||
ServiceName: "http-svc",
|
||||
ServicePort: intstr.IntOrString{
|
||||
|
|
@ -1096,7 +1094,7 @@ func TestGetBackendServers(t *testing.T) {
|
|||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: "/",
|
||||
PathType: &pathPrefix,
|
||||
PathType: &pathTypePrefix,
|
||||
Backend: networking.IngressBackend{
|
||||
ServiceName: "http-svc-canary",
|
||||
ServicePort: intstr.IntOrString{
|
||||
|
|
@ -1165,7 +1163,7 @@ func TestGetBackendServers(t *testing.T) {
|
|||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: "/a",
|
||||
PathType: &pathPrefix,
|
||||
PathType: &pathTypePrefix,
|
||||
Backend: networking.IngressBackend{
|
||||
ServiceName: "http-svc-1",
|
||||
ServicePort: intstr.IntOrString{
|
||||
|
|
@ -1202,7 +1200,7 @@ func TestGetBackendServers(t *testing.T) {
|
|||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: "/a",
|
||||
PathType: &pathPrefix,
|
||||
PathType: &pathTypePrefix,
|
||||
Backend: networking.IngressBackend{
|
||||
ServiceName: "http-svc-2",
|
||||
ServicePort: intstr.IntOrString{
|
||||
|
|
@ -1239,7 +1237,7 @@ func TestGetBackendServers(t *testing.T) {
|
|||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: "/b",
|
||||
PathType: &pathPrefix,
|
||||
PathType: &pathTypePrefix,
|
||||
Backend: networking.IngressBackend{
|
||||
ServiceName: "http-svc-2",
|
||||
ServicePort: intstr.IntOrString{
|
||||
|
|
@ -1276,7 +1274,7 @@ func TestGetBackendServers(t *testing.T) {
|
|||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: "/b",
|
||||
PathType: &pathPrefix,
|
||||
PathType: &pathTypePrefix,
|
||||
Backend: networking.IngressBackend{
|
||||
ServiceName: "http-svc-1",
|
||||
ServicePort: intstr.IntOrString{
|
||||
|
|
@ -1313,7 +1311,7 @@ func TestGetBackendServers(t *testing.T) {
|
|||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: "/c",
|
||||
PathType: &pathPrefix,
|
||||
PathType: &pathTypePrefix,
|
||||
Backend: networking.IngressBackend{
|
||||
ServiceName: "http-svc-1",
|
||||
ServicePort: intstr.IntOrString{
|
||||
|
|
@ -1350,7 +1348,7 @@ func TestGetBackendServers(t *testing.T) {
|
|||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: "/c",
|
||||
PathType: &pathPrefix,
|
||||
PathType: &pathTypePrefix,
|
||||
Backend: networking.IngressBackend{
|
||||
ServiceName: "http-svc-2",
|
||||
ServicePort: intstr.IntOrString{
|
||||
|
|
@ -1435,7 +1433,7 @@ func TestGetBackendServers(t *testing.T) {
|
|||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: "/path1",
|
||||
PathType: &pathPrefix,
|
||||
PathType: &pathTypePrefix,
|
||||
Backend: networking.IngressBackend{
|
||||
ServiceName: "path1-svc",
|
||||
ServicePort: intstr.IntOrString{
|
||||
|
|
@ -1475,7 +1473,7 @@ func TestGetBackendServers(t *testing.T) {
|
|||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: "/path2",
|
||||
PathType: &pathPrefix,
|
||||
PathType: &pathTypePrefix,
|
||||
Backend: networking.IngressBackend{
|
||||
ServiceName: "path2-svc",
|
||||
ServicePort: intstr.IntOrString{
|
||||
|
|
@ -1540,7 +1538,7 @@ func TestGetBackendServers(t *testing.T) {
|
|||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: "/path1",
|
||||
PathType: &pathPrefix,
|
||||
PathType: &pathTypePrefix,
|
||||
Backend: networking.IngressBackend{
|
||||
ServiceName: "path1-svc",
|
||||
ServicePort: intstr.IntOrString{
|
||||
|
|
@ -1580,7 +1578,7 @@ func TestGetBackendServers(t *testing.T) {
|
|||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: "/path2",
|
||||
PathType: &pathPrefix,
|
||||
PathType: &pathTypePrefix,
|
||||
Backend: networking.IngressBackend{
|
||||
ServiceName: "path2-svc",
|
||||
ServicePort: intstr.IntOrString{
|
||||
|
|
|
|||
112
internal/ingress/controller/location.go
Normal file
112
internal/ingress/controller/location.go
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
Copyright 2020 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 controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/mitchellh/copystructure"
|
||||
networking "k8s.io/api/networking/v1beta1"
|
||||
"k8s.io/ingress-nginx/internal/ingress"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
var (
|
||||
pathTypeExact = networking.PathTypeExact
|
||||
pathTypePrefix = networking.PathTypePrefix
|
||||
)
|
||||
|
||||
// updateServerLocations inspects the generated locations configuration for a server
|
||||
// normalizing the path and adding an additional exact location when is possible
|
||||
func updateServerLocations(locations []*ingress.Location) []*ingress.Location {
|
||||
newLocations := []*ingress.Location{}
|
||||
|
||||
// get Exact locations to check if one already exists
|
||||
exactLocations := map[string]*ingress.Location{}
|
||||
for _, location := range locations {
|
||||
if *location.PathType == pathTypeExact {
|
||||
exactLocations[location.Path] = location
|
||||
}
|
||||
}
|
||||
|
||||
for _, location := range locations {
|
||||
// location / does not require any update
|
||||
if location.Path == rootLocation {
|
||||
newLocations = append(newLocations, location)
|
||||
continue
|
||||
}
|
||||
|
||||
// only Prefix locations could require an additional location block
|
||||
if *location.PathType != pathTypePrefix {
|
||||
newLocations = append(newLocations, location)
|
||||
continue
|
||||
}
|
||||
|
||||
// locations with rewrite or using regular expressions are not modified
|
||||
if needsRewrite(location) || location.Rewrite.UseRegex {
|
||||
newLocations = append(newLocations, location)
|
||||
continue
|
||||
}
|
||||
|
||||
// If exists an Exact location is not possible to create a new one.
|
||||
if _, alreadyExists := exactLocations[location.Path]; alreadyExists {
|
||||
// normalize path. Must end in /
|
||||
location.Path = normalizePrefixPath(location.Path)
|
||||
newLocations = append(newLocations, location)
|
||||
continue
|
||||
}
|
||||
|
||||
// copy location before any change
|
||||
el, err := copystructure.Copy(location)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "copying location")
|
||||
}
|
||||
|
||||
// normalize path. Must end in /
|
||||
location.Path = normalizePrefixPath(location.Path)
|
||||
newLocations = append(newLocations, location)
|
||||
|
||||
// add exact location
|
||||
exactLocation := el.(*ingress.Location)
|
||||
exactLocation.PathType = &pathTypeExact
|
||||
|
||||
newLocations = append(newLocations, exactLocation)
|
||||
}
|
||||
|
||||
return newLocations
|
||||
}
|
||||
|
||||
func normalizePrefixPath(path string) string {
|
||||
if path == rootLocation {
|
||||
return rootLocation
|
||||
}
|
||||
|
||||
if !strings.HasSuffix(path, "/") {
|
||||
return fmt.Sprintf("%v/", path)
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
func needsRewrite(location *ingress.Location) bool {
|
||||
if len(location.Rewrite.Target) > 0 && location.Rewrite.Target != location.Path {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
|
@ -317,26 +317,16 @@ func locationConfigForLua(l interface{}, a interface{}) string {
|
|||
return "{}"
|
||||
}
|
||||
|
||||
pathType := ""
|
||||
if location.PathType != nil {
|
||||
pathType = fmt.Sprintf("%v", *location.PathType)
|
||||
}
|
||||
if needsRewrite(location) || location.Rewrite.UseRegex {
|
||||
pathType = ""
|
||||
}
|
||||
|
||||
return fmt.Sprintf(`{
|
||||
force_ssl_redirect = %t,
|
||||
ssl_redirect = %t,
|
||||
force_no_ssl_redirect = %t,
|
||||
use_port_in_redirects = %t,
|
||||
path_type = "%v",
|
||||
}`,
|
||||
location.Rewrite.ForceSSLRedirect,
|
||||
location.Rewrite.SSLRedirect,
|
||||
isLocationInLocationList(l, all.Cfg.NoTLSRedirectLocations),
|
||||
location.UsePortInRedirects,
|
||||
pathType,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -417,7 +407,7 @@ func buildLocation(input interface{}, enforceRegex bool) string {
|
|||
}
|
||||
|
||||
if location.PathType != nil && *location.PathType == networkingv1beta1.PathTypeExact {
|
||||
return fmt.Sprintf(`~ ^%s$`, path)
|
||||
return fmt.Sprintf(`= %s`, path)
|
||||
}
|
||||
|
||||
return path
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue