Fix panic on multiple ingress mess up upstream is primary or not

This commit is contained in:
qianyong 2019-08-29 14:32:43 +08:00
parent 8740c1b661
commit 435377f47f
2 changed files with 286 additions and 9 deletions

View file

@ -1227,9 +1227,16 @@ func mergeAlternativeBackends(ing *ingress.Ingress, upstreams map[string]*ingres
} else {
merged := false
altEqualsPri := false
for _, loc := range servers[defServerName].Locations {
priUps := upstreams[loc.Backend]
altEqualsPri = altUps.Name == priUps.Name
if altEqualsPri {
klog.Warningf("alternative upstream %s in Ingress %s/%s is primary upstream in Other Ingress for location %s%s!",
altUps.Name, ing.Namespace, ing.Name, servers[defServerName].Hostname, loc.Path)
break
}
if canMergeBackend(priUps, altUps) {
klog.V(2).Infof("matching backend %v found for alternative backend %v",
@ -1239,7 +1246,7 @@ func mergeAlternativeBackends(ing *ingress.Ingress, upstreams map[string]*ingres
}
}
if !merged {
if !altEqualsPri && !merged {
klog.Warningf("unable to find real backend for alternative backend %v. Deleting.", altUps.Name)
delete(upstreams, altUps.Name)
}
@ -1258,6 +1265,7 @@ func mergeAlternativeBackends(ing *ingress.Ingress, upstreams map[string]*ingres
}
merged := false
altEqualsPri := false
server, ok := servers[rule.Host]
if !ok {
@ -1271,6 +1279,12 @@ func mergeAlternativeBackends(ing *ingress.Ingress, upstreams map[string]*ingres
// find matching paths
for _, loc := range server.Locations {
priUps := upstreams[loc.Backend]
altEqualsPri = altUps.Name == priUps.Name
if altEqualsPri {
klog.Warningf("alternative upstream %s in Ingress %s/%s is primary upstream in Other Ingress for location %s%s!",
altUps.Name, ing.Namespace, ing.Name, server.Hostname, loc.Path)
break
}
if canMergeBackend(priUps, altUps) && loc.Path == path.Path {
klog.V(2).Infof("matching backend %v found for alternative backend %v",
@ -1280,7 +1294,7 @@ func mergeAlternativeBackends(ing *ingress.Ingress, upstreams map[string]*ingres
}
}
if !merged {
if !altEqualsPri && !merged {
klog.Warningf("unable to find real backend for alternative backend %v. Deleting.", altUps.Name)
delete(upstreams, altUps.Name)
}

View file

@ -818,7 +818,7 @@ func TestGetBackendServers(t *testing.T) {
testCases := []struct {
Ingresses []*ingress.Ingress
Validate func(servers []*ingress.Server)
Validate func(upstreams []*ingress.Backend, servers []*ingress.Server)
}{
{
Ingresses: []*ingress.Ingress{
@ -843,7 +843,7 @@ func TestGetBackendServers(t *testing.T) {
},
},
},
Validate: func(servers []*ingress.Server) {
Validate: func(upstreams []*ingress.Backend, servers []*ingress.Server) {
if len(servers) != 1 {
t.Errorf("servers count should be 1, got %d", len(servers))
return
@ -905,7 +905,7 @@ func TestGetBackendServers(t *testing.T) {
},
},
},
Validate: func(servers []*ingress.Server) {
Validate: func(upstreams []*ingress.Backend, servers []*ingress.Server) {
if len(servers) != 1 {
t.Errorf("servers count should be 1, got %d", len(servers))
return
@ -962,7 +962,7 @@ func TestGetBackendServers(t *testing.T) {
},
},
},
Validate: func(servers []*ingress.Server) {
Validate: func(upstreams []*ingress.Backend, servers []*ingress.Server) {
if len(servers) != 1 {
t.Errorf("servers count should be 1, got %d", len(servers))
return
@ -1056,7 +1056,7 @@ func TestGetBackendServers(t *testing.T) {
},
},
},
Validate: func(servers []*ingress.Server) {
Validate: func(upstreams []*ingress.Backend, servers []*ingress.Server) {
if len(servers) != 2 {
t.Errorf("servers count should be 2, got %d", len(servers))
return
@ -1084,11 +1084,274 @@ func TestGetBackendServers(t *testing.T) {
}
},
},
{
Ingresses: []*ingress.Ingress{
{
Ingress: networking.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "example-a",
Namespace: "example",
},
Spec: networking.IngressSpec{
Rules: []networking.IngressRule{
{
Host: "example.com",
IngressRuleValue: networking.IngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{
Paths: []networking.HTTPIngressPath{
{
Path: "/a",
Backend: networking.IngressBackend{
ServiceName: "http-svc-1",
ServicePort: intstr.IntOrString{
Type: intstr.Int,
IntVal: 80,
},
},
},
},
},
},
},
},
},
},
ParsedAnnotations: &annotations.Ingress{
Canary: canary.Config{
Enabled: false,
},
},
},
{
Ingress: networking.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "example-a-canary",
Namespace: "example",
},
Spec: networking.IngressSpec{
Rules: []networking.IngressRule{
{
Host: "example.com",
IngressRuleValue: networking.IngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{
Paths: []networking.HTTPIngressPath{
{
Path: "/a",
Backend: networking.IngressBackend{
ServiceName: "http-svc-2",
ServicePort: intstr.IntOrString{
Type: intstr.Int,
IntVal: 80,
},
},
},
},
},
},
},
},
},
},
ParsedAnnotations: &annotations.Ingress{
Canary: canary.Config{
Enabled: true,
},
},
},
{
Ingress: networking.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "example-b",
Namespace: "example",
},
Spec: networking.IngressSpec{
Rules: []networking.IngressRule{
{
Host: "example.com",
IngressRuleValue: networking.IngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{
Paths: []networking.HTTPIngressPath{
{
Path: "/b",
Backend: networking.IngressBackend{
ServiceName: "http-svc-2",
ServicePort: intstr.IntOrString{
Type: intstr.Int,
IntVal: 80,
},
},
},
},
},
},
},
},
},
},
ParsedAnnotations: &annotations.Ingress{
Canary: canary.Config{
Enabled: false,
},
},
},
{
Ingress: networking.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "example-b-canary",
Namespace: "example",
},
Spec: networking.IngressSpec{
Rules: []networking.IngressRule{
{
Host: "example.com",
IngressRuleValue: networking.IngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{
Paths: []networking.HTTPIngressPath{
{
Path: "/b",
Backend: networking.IngressBackend{
ServiceName: "http-svc-1",
ServicePort: intstr.IntOrString{
Type: intstr.Int,
IntVal: 80,
},
},
},
},
},
},
},
},
},
},
ParsedAnnotations: &annotations.Ingress{
Canary: canary.Config{
Enabled: true,
},
},
},
{
Ingress: networking.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "example-c",
Namespace: "example",
},
Spec: networking.IngressSpec{
Rules: []networking.IngressRule{
{
Host: "example.com",
IngressRuleValue: networking.IngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{
Paths: []networking.HTTPIngressPath{
{
Path: "/c",
Backend: networking.IngressBackend{
ServiceName: "http-svc-1",
ServicePort: intstr.IntOrString{
Type: intstr.Int,
IntVal: 80,
},
},
},
},
},
},
},
},
},
},
ParsedAnnotations: &annotations.Ingress{
Canary: canary.Config{
Enabled: false,
},
},
},
{
Ingress: networking.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "example-c-canary",
Namespace: "example",
},
Spec: networking.IngressSpec{
Rules: []networking.IngressRule{
{
Host: "example.com",
IngressRuleValue: networking.IngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{
Paths: []networking.HTTPIngressPath{
{
Path: "/c",
Backend: networking.IngressBackend{
ServiceName: "http-svc-2",
ServicePort: intstr.IntOrString{
Type: intstr.Int,
IntVal: 80,
},
},
},
},
},
},
},
},
},
},
ParsedAnnotations: &annotations.Ingress{
Canary: canary.Config{
Enabled: true,
},
},
},
},
Validate: func(upstreams []*ingress.Backend, servers []*ingress.Server) {
if len(servers) != 2 {
t.Errorf("servers count should be 2, got %d", len(servers))
return
}
s := servers[0]
if s.Hostname != "_" {
t.Errorf("server hostname should be '_', got '%s'", s.Hostname)
}
if !s.Locations[0].IsDefBackend {
t.Errorf("server location 0 should be default backend")
}
if s.Locations[0].Backend != defUpstreamName {
t.Errorf("location backend should be '%s', got '%s'", defUpstreamName, s.Locations[0].Backend)
}
s = servers[1]
if s.Hostname != "example.com" {
t.Errorf("server hostname should be 'example.com', got '%s'", s.Hostname)
}
if s.Locations[0].Backend != "example-http-svc-1-80" || s.Locations[1].Backend != "example-http-svc-1-80" || s.Locations[2].Backend != "example-http-svc-1-80" {
t.Errorf("all location backend should be 'example-http-svc-1-80'")
}
if len(upstreams) != 3 {
t.Errorf("upstreams count should be 3, got %d", len(upstreams))
return
}
if upstreams[0].Name != "example-http-svc-1-80" {
t.Errorf("example-http-svc-1-80 should be frist upstream, got %s", upstreams[0].Name)
return
}
if upstreams[0].NoServer {
t.Errorf("'example-http-svc-1-80' should be primary upstream, got as alternative upstream")
}
if len(upstreams[0].AlternativeBackends) != 1 || upstreams[0].AlternativeBackends[0] != "example-http-svc-2-80" {
t.Errorf("example-http-svc-2-80 should be alternative upstream for 'example-http-svc-1-80'")
}
},
},
}
for _, testCase := range testCases {
_, servers := ctl.getBackendServers(testCase.Ingresses)
testCase.Validate(servers)
upstreams, servers := ctl.getBackendServers(testCase.Ingresses)
testCase.Validate(upstreams, servers)
}
}