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
1
go.mod
1
go.mod
|
@ -11,6 +11,7 @@ require (
|
||||||
github.com/imdario/mergo v0.3.10
|
github.com/imdario/mergo v0.3.10
|
||||||
github.com/json-iterator/go v1.1.10
|
github.com/json-iterator/go v1.1.10
|
||||||
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348
|
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348
|
||||||
|
github.com/mitchellh/copystructure v1.0.0
|
||||||
github.com/mitchellh/go-ps v1.0.0
|
github.com/mitchellh/go-ps v1.0.0
|
||||||
github.com/mitchellh/hashstructure v1.0.0
|
github.com/mitchellh/hashstructure v1.0.0
|
||||||
github.com/mitchellh/mapstructure v1.3.2
|
github.com/mitchellh/mapstructure v1.3.2
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -421,6 +421,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182aff
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||||
|
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
|
||||||
|
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
||||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc=
|
github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc=
|
||||||
|
@ -435,6 +437,8 @@ github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQz
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg=
|
github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg=
|
||||||
github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
|
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
|
||||||
|
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||||
github.com/mmarkdown/mmark v2.0.40+incompatible h1:vMeUeDzBK3H+/mU0oMVfMuhSXJlIA+DE/DMPQNAj5C4=
|
github.com/mmarkdown/mmark v2.0.40+incompatible h1:vMeUeDzBK3H+/mU0oMVfMuhSXJlIA+DE/DMPQNAj5C4=
|
||||||
github.com/mmarkdown/mmark v2.0.40+incompatible/go.mod h1:Uvmoz7tvsWpr7bMVxIpqZPyN3FbOtzDmnsJDFp7ltJs=
|
github.com/mmarkdown/mmark v2.0.40+incompatible/go.mod h1:Uvmoz7tvsWpr7bMVxIpqZPyN3FbOtzDmnsJDFp7ltJs=
|
||||||
github.com/moby/sys/mountinfo v0.1.3/go.mod h1:w2t2Avltqx8vE7gX5l+QiBKxODu2TX0+Syr3h52Tw4o=
|
github.com/moby/sys/mountinfo v0.1.3/go.mod h1:w2t2Avltqx8vE7gX5l+QiBKxODu2TX0+Syr3h52Tw4o=
|
||||||
|
|
|
@ -430,6 +430,20 @@ func (n *NGINXController) getConfiguration(ingresses []*ingress.Ingress) (sets.S
|
||||||
hosts := sets.NewString()
|
hosts := sets.NewString()
|
||||||
|
|
||||||
for _, server := range servers {
|
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) {
|
if !hosts.Has(server.Hostname) {
|
||||||
hosts.Insert(server.Hostname)
|
hosts.Insert(server.Hostname)
|
||||||
}
|
}
|
||||||
|
|
|
@ -270,8 +270,6 @@ func TestCheckIngress(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
var pathPrefix = networking.PathTypePrefix
|
|
||||||
|
|
||||||
func TestMergeAlternativeBackends(t *testing.T) {
|
func TestMergeAlternativeBackends(t *testing.T) {
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
ingress *ingress.Ingress
|
ingress *ingress.Ingress
|
||||||
|
@ -295,7 +293,7 @@ func TestMergeAlternativeBackends(t *testing.T) {
|
||||||
Paths: []networking.HTTPIngressPath{
|
Paths: []networking.HTTPIngressPath{
|
||||||
{
|
{
|
||||||
Path: "/",
|
Path: "/",
|
||||||
PathType: &pathPrefix,
|
PathType: &pathTypePrefix,
|
||||||
Backend: networking.IngressBackend{
|
Backend: networking.IngressBackend{
|
||||||
ServiceName: "http-svc-canary",
|
ServiceName: "http-svc-canary",
|
||||||
ServicePort: intstr.IntOrString{
|
ServicePort: intstr.IntOrString{
|
||||||
|
@ -331,7 +329,7 @@ func TestMergeAlternativeBackends(t *testing.T) {
|
||||||
Locations: []*ingress.Location{
|
Locations: []*ingress.Location{
|
||||||
{
|
{
|
||||||
Path: "/",
|
Path: "/",
|
||||||
PathType: &pathPrefix,
|
PathType: &pathTypePrefix,
|
||||||
Backend: "example-http-svc-80",
|
Backend: "example-http-svc-80",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -357,7 +355,7 @@ func TestMergeAlternativeBackends(t *testing.T) {
|
||||||
Locations: []*ingress.Location{
|
Locations: []*ingress.Location{
|
||||||
{
|
{
|
||||||
Path: "/",
|
Path: "/",
|
||||||
PathType: &pathPrefix,
|
PathType: &pathTypePrefix,
|
||||||
Backend: "example-http-svc-80",
|
Backend: "example-http-svc-80",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -379,7 +377,7 @@ func TestMergeAlternativeBackends(t *testing.T) {
|
||||||
Paths: []networking.HTTPIngressPath{
|
Paths: []networking.HTTPIngressPath{
|
||||||
{
|
{
|
||||||
Path: "/",
|
Path: "/",
|
||||||
PathType: &pathPrefix,
|
PathType: &pathTypePrefix,
|
||||||
Backend: networking.IngressBackend{
|
Backend: networking.IngressBackend{
|
||||||
ServiceName: "foo-http-svc-canary",
|
ServiceName: "foo-http-svc-canary",
|
||||||
ServicePort: intstr.IntOrString{
|
ServicePort: intstr.IntOrString{
|
||||||
|
@ -399,7 +397,7 @@ func TestMergeAlternativeBackends(t *testing.T) {
|
||||||
Paths: []networking.HTTPIngressPath{
|
Paths: []networking.HTTPIngressPath{
|
||||||
{
|
{
|
||||||
Path: "/",
|
Path: "/",
|
||||||
PathType: &pathPrefix,
|
PathType: &pathTypePrefix,
|
||||||
Backend: networking.IngressBackend{
|
Backend: networking.IngressBackend{
|
||||||
ServiceName: "http-svc-canary",
|
ServiceName: "http-svc-canary",
|
||||||
ServicePort: intstr.IntOrString{
|
ServicePort: intstr.IntOrString{
|
||||||
|
@ -447,7 +445,7 @@ func TestMergeAlternativeBackends(t *testing.T) {
|
||||||
Locations: []*ingress.Location{
|
Locations: []*ingress.Location{
|
||||||
{
|
{
|
||||||
Path: "/",
|
Path: "/",
|
||||||
PathType: &pathPrefix,
|
PathType: &pathTypePrefix,
|
||||||
Backend: "example-foo-http-svc-80",
|
Backend: "example-foo-http-svc-80",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -457,7 +455,7 @@ func TestMergeAlternativeBackends(t *testing.T) {
|
||||||
Locations: []*ingress.Location{
|
Locations: []*ingress.Location{
|
||||||
{
|
{
|
||||||
Path: "/",
|
Path: "/",
|
||||||
PathType: &pathPrefix,
|
PathType: &pathTypePrefix,
|
||||||
Backend: "example-http-svc-80",
|
Backend: "example-http-svc-80",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -495,7 +493,7 @@ func TestMergeAlternativeBackends(t *testing.T) {
|
||||||
Locations: []*ingress.Location{
|
Locations: []*ingress.Location{
|
||||||
{
|
{
|
||||||
Path: "/",
|
Path: "/",
|
||||||
PathType: &pathPrefix,
|
PathType: &pathTypePrefix,
|
||||||
Backend: "example-http-svc-80",
|
Backend: "example-http-svc-80",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -517,7 +515,7 @@ func TestMergeAlternativeBackends(t *testing.T) {
|
||||||
Paths: []networking.HTTPIngressPath{
|
Paths: []networking.HTTPIngressPath{
|
||||||
{
|
{
|
||||||
Path: "/",
|
Path: "/",
|
||||||
PathType: &pathPrefix,
|
PathType: &pathTypePrefix,
|
||||||
Backend: networking.IngressBackend{
|
Backend: networking.IngressBackend{
|
||||||
ServiceName: "http-svc-canary",
|
ServiceName: "http-svc-canary",
|
||||||
ServicePort: intstr.IntOrString{
|
ServicePort: intstr.IntOrString{
|
||||||
|
@ -582,7 +580,7 @@ func TestMergeAlternativeBackends(t *testing.T) {
|
||||||
Locations: []*ingress.Location{
|
Locations: []*ingress.Location{
|
||||||
{
|
{
|
||||||
Path: "/",
|
Path: "/",
|
||||||
PathType: &pathPrefix,
|
PathType: &pathTypePrefix,
|
||||||
Backend: "example-http-svc-80",
|
Backend: "example-http-svc-80",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -608,7 +606,7 @@ func TestMergeAlternativeBackends(t *testing.T) {
|
||||||
Locations: []*ingress.Location{
|
Locations: []*ingress.Location{
|
||||||
{
|
{
|
||||||
Path: "/",
|
Path: "/",
|
||||||
PathType: &pathPrefix,
|
PathType: &pathTypePrefix,
|
||||||
Backend: "example-http-svc-80",
|
Backend: "example-http-svc-80",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -650,7 +648,7 @@ func TestMergeAlternativeBackends(t *testing.T) {
|
||||||
Locations: []*ingress.Location{
|
Locations: []*ingress.Location{
|
||||||
{
|
{
|
||||||
Path: "/",
|
Path: "/",
|
||||||
PathType: &pathPrefix,
|
PathType: &pathTypePrefix,
|
||||||
Backend: "upstream-default-backend",
|
Backend: "upstream-default-backend",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -663,7 +661,7 @@ func TestMergeAlternativeBackends(t *testing.T) {
|
||||||
Locations: []*ingress.Location{
|
Locations: []*ingress.Location{
|
||||||
{
|
{
|
||||||
Path: "/",
|
Path: "/",
|
||||||
PathType: &pathPrefix,
|
PathType: &pathTypePrefix,
|
||||||
Backend: "upstream-default-backend",
|
Backend: "upstream-default-backend",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -999,7 +997,7 @@ func TestGetBackendServers(t *testing.T) {
|
||||||
Paths: []networking.HTTPIngressPath{
|
Paths: []networking.HTTPIngressPath{
|
||||||
{
|
{
|
||||||
Path: "/",
|
Path: "/",
|
||||||
PathType: &pathPrefix,
|
PathType: &pathTypePrefix,
|
||||||
Backend: networking.IngressBackend{
|
Backend: networking.IngressBackend{
|
||||||
ServiceName: "http-svc-canary",
|
ServiceName: "http-svc-canary",
|
||||||
ServicePort: intstr.IntOrString{
|
ServicePort: intstr.IntOrString{
|
||||||
|
@ -1059,7 +1057,7 @@ func TestGetBackendServers(t *testing.T) {
|
||||||
Paths: []networking.HTTPIngressPath{
|
Paths: []networking.HTTPIngressPath{
|
||||||
{
|
{
|
||||||
Path: "/",
|
Path: "/",
|
||||||
PathType: &pathPrefix,
|
PathType: &pathTypePrefix,
|
||||||
Backend: networking.IngressBackend{
|
Backend: networking.IngressBackend{
|
||||||
ServiceName: "http-svc",
|
ServiceName: "http-svc",
|
||||||
ServicePort: intstr.IntOrString{
|
ServicePort: intstr.IntOrString{
|
||||||
|
@ -1096,7 +1094,7 @@ func TestGetBackendServers(t *testing.T) {
|
||||||
Paths: []networking.HTTPIngressPath{
|
Paths: []networking.HTTPIngressPath{
|
||||||
{
|
{
|
||||||
Path: "/",
|
Path: "/",
|
||||||
PathType: &pathPrefix,
|
PathType: &pathTypePrefix,
|
||||||
Backend: networking.IngressBackend{
|
Backend: networking.IngressBackend{
|
||||||
ServiceName: "http-svc-canary",
|
ServiceName: "http-svc-canary",
|
||||||
ServicePort: intstr.IntOrString{
|
ServicePort: intstr.IntOrString{
|
||||||
|
@ -1165,7 +1163,7 @@ func TestGetBackendServers(t *testing.T) {
|
||||||
Paths: []networking.HTTPIngressPath{
|
Paths: []networking.HTTPIngressPath{
|
||||||
{
|
{
|
||||||
Path: "/a",
|
Path: "/a",
|
||||||
PathType: &pathPrefix,
|
PathType: &pathTypePrefix,
|
||||||
Backend: networking.IngressBackend{
|
Backend: networking.IngressBackend{
|
||||||
ServiceName: "http-svc-1",
|
ServiceName: "http-svc-1",
|
||||||
ServicePort: intstr.IntOrString{
|
ServicePort: intstr.IntOrString{
|
||||||
|
@ -1202,7 +1200,7 @@ func TestGetBackendServers(t *testing.T) {
|
||||||
Paths: []networking.HTTPIngressPath{
|
Paths: []networking.HTTPIngressPath{
|
||||||
{
|
{
|
||||||
Path: "/a",
|
Path: "/a",
|
||||||
PathType: &pathPrefix,
|
PathType: &pathTypePrefix,
|
||||||
Backend: networking.IngressBackend{
|
Backend: networking.IngressBackend{
|
||||||
ServiceName: "http-svc-2",
|
ServiceName: "http-svc-2",
|
||||||
ServicePort: intstr.IntOrString{
|
ServicePort: intstr.IntOrString{
|
||||||
|
@ -1239,7 +1237,7 @@ func TestGetBackendServers(t *testing.T) {
|
||||||
Paths: []networking.HTTPIngressPath{
|
Paths: []networking.HTTPIngressPath{
|
||||||
{
|
{
|
||||||
Path: "/b",
|
Path: "/b",
|
||||||
PathType: &pathPrefix,
|
PathType: &pathTypePrefix,
|
||||||
Backend: networking.IngressBackend{
|
Backend: networking.IngressBackend{
|
||||||
ServiceName: "http-svc-2",
|
ServiceName: "http-svc-2",
|
||||||
ServicePort: intstr.IntOrString{
|
ServicePort: intstr.IntOrString{
|
||||||
|
@ -1276,7 +1274,7 @@ func TestGetBackendServers(t *testing.T) {
|
||||||
Paths: []networking.HTTPIngressPath{
|
Paths: []networking.HTTPIngressPath{
|
||||||
{
|
{
|
||||||
Path: "/b",
|
Path: "/b",
|
||||||
PathType: &pathPrefix,
|
PathType: &pathTypePrefix,
|
||||||
Backend: networking.IngressBackend{
|
Backend: networking.IngressBackend{
|
||||||
ServiceName: "http-svc-1",
|
ServiceName: "http-svc-1",
|
||||||
ServicePort: intstr.IntOrString{
|
ServicePort: intstr.IntOrString{
|
||||||
|
@ -1313,7 +1311,7 @@ func TestGetBackendServers(t *testing.T) {
|
||||||
Paths: []networking.HTTPIngressPath{
|
Paths: []networking.HTTPIngressPath{
|
||||||
{
|
{
|
||||||
Path: "/c",
|
Path: "/c",
|
||||||
PathType: &pathPrefix,
|
PathType: &pathTypePrefix,
|
||||||
Backend: networking.IngressBackend{
|
Backend: networking.IngressBackend{
|
||||||
ServiceName: "http-svc-1",
|
ServiceName: "http-svc-1",
|
||||||
ServicePort: intstr.IntOrString{
|
ServicePort: intstr.IntOrString{
|
||||||
|
@ -1350,7 +1348,7 @@ func TestGetBackendServers(t *testing.T) {
|
||||||
Paths: []networking.HTTPIngressPath{
|
Paths: []networking.HTTPIngressPath{
|
||||||
{
|
{
|
||||||
Path: "/c",
|
Path: "/c",
|
||||||
PathType: &pathPrefix,
|
PathType: &pathTypePrefix,
|
||||||
Backend: networking.IngressBackend{
|
Backend: networking.IngressBackend{
|
||||||
ServiceName: "http-svc-2",
|
ServiceName: "http-svc-2",
|
||||||
ServicePort: intstr.IntOrString{
|
ServicePort: intstr.IntOrString{
|
||||||
|
@ -1435,7 +1433,7 @@ func TestGetBackendServers(t *testing.T) {
|
||||||
Paths: []networking.HTTPIngressPath{
|
Paths: []networking.HTTPIngressPath{
|
||||||
{
|
{
|
||||||
Path: "/path1",
|
Path: "/path1",
|
||||||
PathType: &pathPrefix,
|
PathType: &pathTypePrefix,
|
||||||
Backend: networking.IngressBackend{
|
Backend: networking.IngressBackend{
|
||||||
ServiceName: "path1-svc",
|
ServiceName: "path1-svc",
|
||||||
ServicePort: intstr.IntOrString{
|
ServicePort: intstr.IntOrString{
|
||||||
|
@ -1475,7 +1473,7 @@ func TestGetBackendServers(t *testing.T) {
|
||||||
Paths: []networking.HTTPIngressPath{
|
Paths: []networking.HTTPIngressPath{
|
||||||
{
|
{
|
||||||
Path: "/path2",
|
Path: "/path2",
|
||||||
PathType: &pathPrefix,
|
PathType: &pathTypePrefix,
|
||||||
Backend: networking.IngressBackend{
|
Backend: networking.IngressBackend{
|
||||||
ServiceName: "path2-svc",
|
ServiceName: "path2-svc",
|
||||||
ServicePort: intstr.IntOrString{
|
ServicePort: intstr.IntOrString{
|
||||||
|
@ -1540,7 +1538,7 @@ func TestGetBackendServers(t *testing.T) {
|
||||||
Paths: []networking.HTTPIngressPath{
|
Paths: []networking.HTTPIngressPath{
|
||||||
{
|
{
|
||||||
Path: "/path1",
|
Path: "/path1",
|
||||||
PathType: &pathPrefix,
|
PathType: &pathTypePrefix,
|
||||||
Backend: networking.IngressBackend{
|
Backend: networking.IngressBackend{
|
||||||
ServiceName: "path1-svc",
|
ServiceName: "path1-svc",
|
||||||
ServicePort: intstr.IntOrString{
|
ServicePort: intstr.IntOrString{
|
||||||
|
@ -1580,7 +1578,7 @@ func TestGetBackendServers(t *testing.T) {
|
||||||
Paths: []networking.HTTPIngressPath{
|
Paths: []networking.HTTPIngressPath{
|
||||||
{
|
{
|
||||||
Path: "/path2",
|
Path: "/path2",
|
||||||
PathType: &pathPrefix,
|
PathType: &pathTypePrefix,
|
||||||
Backend: networking.IngressBackend{
|
Backend: networking.IngressBackend{
|
||||||
ServiceName: "path2-svc",
|
ServiceName: "path2-svc",
|
||||||
ServicePort: intstr.IntOrString{
|
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 "{}"
|
return "{}"
|
||||||
}
|
}
|
||||||
|
|
||||||
pathType := ""
|
|
||||||
if location.PathType != nil {
|
|
||||||
pathType = fmt.Sprintf("%v", *location.PathType)
|
|
||||||
}
|
|
||||||
if needsRewrite(location) || location.Rewrite.UseRegex {
|
|
||||||
pathType = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf(`{
|
return fmt.Sprintf(`{
|
||||||
force_ssl_redirect = %t,
|
force_ssl_redirect = %t,
|
||||||
ssl_redirect = %t,
|
ssl_redirect = %t,
|
||||||
force_no_ssl_redirect = %t,
|
force_no_ssl_redirect = %t,
|
||||||
use_port_in_redirects = %t,
|
use_port_in_redirects = %t,
|
||||||
path_type = "%v",
|
|
||||||
}`,
|
}`,
|
||||||
location.Rewrite.ForceSSLRedirect,
|
location.Rewrite.ForceSSLRedirect,
|
||||||
location.Rewrite.SSLRedirect,
|
location.Rewrite.SSLRedirect,
|
||||||
isLocationInLocationList(l, all.Cfg.NoTLSRedirectLocations),
|
isLocationInLocationList(l, all.Cfg.NoTLSRedirectLocations),
|
||||||
location.UsePortInRedirects,
|
location.UsePortInRedirects,
|
||||||
pathType,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,7 +407,7 @@ func buildLocation(input interface{}, enforceRegex bool) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
if location.PathType != nil && *location.PathType == networkingv1beta1.PathTypeExact {
|
if location.PathType != nil && *location.PathType == networkingv1beta1.PathTypeExact {
|
||||||
return fmt.Sprintf(`~ ^%s$`, path)
|
return fmt.Sprintf(`= %s`, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
return path
|
return path
|
||||||
|
|
|
@ -97,25 +97,6 @@ local function parse_x_forwarded_host()
|
||||||
return hosts[1]
|
return hosts[1]
|
||||||
end
|
end
|
||||||
|
|
||||||
local function k8s_matches_pathtype_prefix(current_uri, prefix)
|
|
||||||
if prefix == "/" then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
if current_uri == prefix then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
if #current_uri < #prefix then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
local _, to = string.find(current_uri, prefix)
|
|
||||||
if to == nil then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
return string.sub(current_uri, to + 1, to + 1) == "/"
|
|
||||||
end
|
|
||||||
|
|
||||||
function _M.init_worker()
|
function _M.init_worker()
|
||||||
randomseed()
|
randomseed()
|
||||||
end
|
end
|
||||||
|
@ -128,12 +109,6 @@ end
|
||||||
-- This is where we do variable assignments to be used in subsequent
|
-- This is where we do variable assignments to be used in subsequent
|
||||||
-- phases or redirection
|
-- phases or redirection
|
||||||
function _M.rewrite(location_config)
|
function _M.rewrite(location_config)
|
||||||
if location_config.path_type == "Prefix" and
|
|
||||||
not k8s_matches_pathtype_prefix(ngx.var.uri, ngx.var.location_path) then
|
|
||||||
|
|
||||||
return ngx.exit(ngx.HTTP_NOT_FOUND)
|
|
||||||
end
|
|
||||||
|
|
||||||
ngx.var.pass_access_scheme = ngx.var.scheme
|
ngx.var.pass_access_scheme = ngx.var.scheme
|
||||||
|
|
||||||
ngx.var.best_http_host = ngx.var.http_host or ngx.var.host
|
ngx.var.best_http_host = ngx.var.http_host or ngx.var.host
|
||||||
|
|
|
@ -95,7 +95,8 @@ var _ = framework.DescribeAnnotation("rewrite-target use-regex enable-rewrite-lo
|
||||||
|
|
||||||
f.WaitForNginxServer(host,
|
f.WaitForNginxServer(host,
|
||||||
func(server string) bool {
|
func(server string) bool {
|
||||||
return strings.Contains(server, `location ~* "^/" {`) && strings.Contains(server, `location ~* "^/.well-known/acme/challenge" {`)
|
return strings.Contains(server, `location ~* "^/" {`) &&
|
||||||
|
strings.Contains(server, `location ~* "^/.well-known/acme/challenge" {`)
|
||||||
})
|
})
|
||||||
|
|
||||||
ginkgo.By("making a second request to the non-rewritten location")
|
ginkgo.By("making a second request to the non-rewritten location")
|
||||||
|
@ -116,7 +117,7 @@ var _ = framework.DescribeAnnotation("rewrite-target use-regex enable-rewrite-lo
|
||||||
|
|
||||||
f.WaitForNginxServer(host,
|
f.WaitForNginxServer(host,
|
||||||
func(server string) bool {
|
func(server string) bool {
|
||||||
return strings.Contains(server, "location /foo {")
|
return strings.Contains(server, "location /foo/ {")
|
||||||
})
|
})
|
||||||
|
|
||||||
ginkgo.By(`creating an ingress definition with the use-regex amd rewrite-target annotation`)
|
ginkgo.By(`creating an ingress definition with the use-regex amd rewrite-target annotation`)
|
||||||
|
@ -129,7 +130,8 @@ var _ = framework.DescribeAnnotation("rewrite-target use-regex enable-rewrite-lo
|
||||||
|
|
||||||
f.WaitForNginxServer(host,
|
f.WaitForNginxServer(host,
|
||||||
func(server string) bool {
|
func(server string) bool {
|
||||||
return strings.Contains(server, `location ~* "^/foo" {`) && strings.Contains(server, `location ~* "^/foo.+" {`)
|
return strings.Contains(server, `location ~* "^/foo" {`) &&
|
||||||
|
strings.Contains(server, `location ~* "^/foo.+" {`)
|
||||||
})
|
})
|
||||||
|
|
||||||
ginkgo.By("ensuring '/foo' matches '~* ^/foo'")
|
ginkgo.By("ensuring '/foo' matches '~* ^/foo'")
|
||||||
|
|
|
@ -60,8 +60,8 @@ var _ = framework.IngressNginxDescribe("[Ingress] [PathType] exact", func() {
|
||||||
f.WaitForNginxServer(host,
|
f.WaitForNginxServer(host,
|
||||||
func(server string) bool {
|
func(server string) bool {
|
||||||
return strings.Contains(server, host) &&
|
return strings.Contains(server, host) &&
|
||||||
strings.Contains(server, "location ~ ^/exact$") &&
|
strings.Contains(server, "location = /exact") &&
|
||||||
strings.Contains(server, "location /exact")
|
strings.Contains(server, "location /exact/")
|
||||||
})
|
})
|
||||||
|
|
||||||
body := f.HTTPTestClient().
|
body := f.HTTPTestClient().
|
||||||
|
@ -98,8 +98,8 @@ var _ = framework.IngressNginxDescribe("[Ingress] [PathType] exact", func() {
|
||||||
f.WaitForNginxServer(host,
|
f.WaitForNginxServer(host,
|
||||||
func(server string) bool {
|
func(server string) bool {
|
||||||
return strings.Contains(server, host) &&
|
return strings.Contains(server, host) &&
|
||||||
strings.Contains(server, "location ~ ^/exact$") &&
|
strings.Contains(server, "location = /exact") &&
|
||||||
strings.Contains(server, "location /exact")
|
strings.Contains(server, "location /exact/")
|
||||||
})
|
})
|
||||||
|
|
||||||
body = f.HTTPTestClient().
|
body = f.HTTPTestClient().
|
||||||
|
|
149
test/e2e/ingress/pathtype_mixed.go
Normal file
149
test/e2e/ingress/pathtype_mixed.go
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
/*
|
||||||
|
Copyright 2019 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 ingress
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/onsi/ginkgo"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
networkingv1beta1 "k8s.io/api/networking/v1beta1"
|
||||||
|
"k8s.io/ingress-nginx/test/e2e/framework"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = framework.IngressNginxDescribe("[Ingress] [PathType] mix Exact and Prefix paths", func() {
|
||||||
|
f := framework.NewDefaultFramework("mixed")
|
||||||
|
|
||||||
|
ginkgo.BeforeEach(func() {
|
||||||
|
f.NewEchoDeployment()
|
||||||
|
})
|
||||||
|
|
||||||
|
var exactPathType = networkingv1beta1.PathTypeExact
|
||||||
|
|
||||||
|
ginkgo.It("should choose the correct location", func() {
|
||||||
|
if !f.IsIngressV1Beta1Ready {
|
||||||
|
ginkgo.Skip("Test requires Kubernetes v1.18 or higher")
|
||||||
|
}
|
||||||
|
|
||||||
|
host := "mixed.path"
|
||||||
|
|
||||||
|
annotations := map[string]string{
|
||||||
|
"nginx.ingress.kubernetes.io/configuration-snippet": `more_set_input_headers "pathType: exact";more_set_input_headers "pathlocation: /";`,
|
||||||
|
}
|
||||||
|
ing := framework.NewSingleIngress("exact-root", "/", host, f.Namespace, framework.EchoService, 80, annotations)
|
||||||
|
ing.Spec.Rules[0].IngressRuleValue.HTTP.Paths[0].PathType = &exactPathType
|
||||||
|
f.EnsureIngress(ing)
|
||||||
|
|
||||||
|
annotations = map[string]string{
|
||||||
|
"nginx.ingress.kubernetes.io/configuration-snippet": `more_set_input_headers "pathType: prefix";more_set_input_headers "pathlocation: /";`,
|
||||||
|
}
|
||||||
|
ing = framework.NewSingleIngress("prefix-root", "/", host, f.Namespace, framework.EchoService, 80, annotations)
|
||||||
|
f.EnsureIngress(ing)
|
||||||
|
|
||||||
|
f.WaitForNginxServer(host,
|
||||||
|
func(server string) bool {
|
||||||
|
return strings.Contains(server, host) &&
|
||||||
|
strings.Contains(server, "location = /") &&
|
||||||
|
strings.Contains(server, "location /")
|
||||||
|
})
|
||||||
|
|
||||||
|
ginkgo.By("Checking exact request to /")
|
||||||
|
body := f.HTTPTestClient().
|
||||||
|
GET("/").
|
||||||
|
WithHeader("Host", host).
|
||||||
|
Expect().
|
||||||
|
Status(http.StatusOK).
|
||||||
|
Body().
|
||||||
|
Raw()
|
||||||
|
|
||||||
|
assert.NotContains(ginkgo.GinkgoT(), body, "pathtype=prefix")
|
||||||
|
assert.Contains(ginkgo.GinkgoT(), body, "pathtype=exact")
|
||||||
|
assert.Contains(ginkgo.GinkgoT(), body, "pathlocation=/")
|
||||||
|
|
||||||
|
ginkgo.By("Checking prefix request to /bar")
|
||||||
|
body = f.HTTPTestClient().
|
||||||
|
GET("/bar").
|
||||||
|
WithHeader("Host", host).
|
||||||
|
Expect().
|
||||||
|
Status(http.StatusOK).
|
||||||
|
Body().
|
||||||
|
Raw()
|
||||||
|
|
||||||
|
assert.Contains(ginkgo.GinkgoT(), body, "pathtype=prefix")
|
||||||
|
assert.NotContains(ginkgo.GinkgoT(), body, "pathtype=exact")
|
||||||
|
assert.Contains(ginkgo.GinkgoT(), body, "pathlocation=/")
|
||||||
|
|
||||||
|
annotations = map[string]string{
|
||||||
|
"nginx.ingress.kubernetes.io/configuration-snippet": `more_set_input_headers "pathType: exact";more_set_input_headers "pathlocation: /foo";`,
|
||||||
|
}
|
||||||
|
ing = framework.NewSingleIngress("exact-foo", "/foo", host, f.Namespace, framework.EchoService, 80, annotations)
|
||||||
|
ing.Spec.Rules[0].IngressRuleValue.HTTP.Paths[0].PathType = &exactPathType
|
||||||
|
f.EnsureIngress(ing)
|
||||||
|
|
||||||
|
annotations = map[string]string{
|
||||||
|
"nginx.ingress.kubernetes.io/configuration-snippet": `more_set_input_headers "pathType: prefix";more_set_input_headers "pathlocation: /foo";`,
|
||||||
|
}
|
||||||
|
ing = framework.NewSingleIngress("prefix-foo", "/foo", host, f.Namespace, framework.EchoService, 80, annotations)
|
||||||
|
f.EnsureIngress(ing)
|
||||||
|
|
||||||
|
f.WaitForNginxServer(host,
|
||||||
|
func(server string) bool {
|
||||||
|
return strings.Contains(server, host) &&
|
||||||
|
strings.Contains(server, "location = /foo") &&
|
||||||
|
strings.Contains(server, "location /foo/")
|
||||||
|
})
|
||||||
|
|
||||||
|
ginkgo.By("Checking exact request to /foo")
|
||||||
|
body = f.HTTPTestClient().
|
||||||
|
GET("/foo").
|
||||||
|
WithHeader("Host", host).
|
||||||
|
Expect().
|
||||||
|
Status(http.StatusOK).
|
||||||
|
Body().
|
||||||
|
Raw()
|
||||||
|
|
||||||
|
assert.NotContains(ginkgo.GinkgoT(), body, "pathtype=prefix")
|
||||||
|
assert.Contains(ginkgo.GinkgoT(), body, "pathtype=exact")
|
||||||
|
assert.Contains(ginkgo.GinkgoT(), body, "pathlocation=/foo")
|
||||||
|
|
||||||
|
ginkgo.By("Checking prefix request to /foo/bar")
|
||||||
|
body = f.HTTPTestClient().
|
||||||
|
GET("/foo/bar").
|
||||||
|
WithHeader("Host", host).
|
||||||
|
Expect().
|
||||||
|
Status(http.StatusOK).
|
||||||
|
Body().
|
||||||
|
Raw()
|
||||||
|
|
||||||
|
assert.Contains(ginkgo.GinkgoT(), body, "pathtype=prefix")
|
||||||
|
assert.Contains(ginkgo.GinkgoT(), body, "pathlocation=/foo")
|
||||||
|
|
||||||
|
ginkgo.By("Checking prefix request to /foobar")
|
||||||
|
body = f.HTTPTestClient().
|
||||||
|
GET("/foobar").
|
||||||
|
WithHeader("Host", host).
|
||||||
|
Expect().
|
||||||
|
Status(http.StatusOK).
|
||||||
|
Body().
|
||||||
|
Raw()
|
||||||
|
|
||||||
|
assert.Contains(ginkgo.GinkgoT(), body, "pathtype=prefix")
|
||||||
|
assert.Contains(ginkgo.GinkgoT(), body, "pathlocation=/")
|
||||||
|
})
|
||||||
|
})
|
Loading…
Reference in a new issue