Skip to content

Commit 0ed6443

Browse files
committed
BUG/MEDIUM: services: don't create frontend if corresponding default_backend is
not ready Creating tcp frontend while default_backend is not available yet (for example no matching service) will result in haproxy rejecting configuration and aborting Controller transaction
1 parent 3649d4c commit 0ed6443

File tree

1 file changed

+76
-66
lines changed

1 file changed

+76
-66
lines changed

controller/handler-tcp.go

Lines changed: 76 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/haproxytech/kubernetes-ingress/controller/haproxy/api"
99
ingressRoute "github.com/haproxytech/kubernetes-ingress/controller/ingress"
1010
"github.com/haproxytech/kubernetes-ingress/controller/store"
11+
"github.com/haproxytech/kubernetes-ingress/controller/utils"
1112
"github.com/haproxytech/models/v2"
1213
)
1314

@@ -18,12 +19,12 @@ func (t TCPHandler) Update(k store.K8s, cfg *Configuration, api api.HAProxyClien
1819
if k.ConfigMaps[TCPServices] == nil {
1920
return false, nil
2021
}
21-
for port, svc := range k.ConfigMaps[TCPServices].Annotations {
22+
for port, tcpSvc := range k.ConfigMaps[TCPServices].Annotations {
2223
// Get TCP service from ConfigMap
2324
// parts[0]: Service Name
2425
// parts[1]: Service Port
2526
// parts[2]: SSL option
26-
parts := strings.Split(svc.Value, ":")
27+
parts := strings.Split(tcpSvc.Value, ":")
2728
svcPort := parts[1]
2829
var sslOption string
2930
if len(parts) > 2 {
@@ -36,72 +37,30 @@ func (t TCPHandler) Update(k store.K8s, cfg *Configuration, api api.HAProxyClien
3637
}
3738
namespace := svcName[0]
3839
service := svcName[1]
39-
40-
// Handle Frontend
41-
var frontendName, backendName string
42-
if svc.Status != EMPTY {
43-
backendName = fmt.Sprintf("%s-%s-%s", svcName[0], svcName[1], svcPort)
44-
frontendName = fmt.Sprintf("tcp-%s", port)
40+
if _, ok := k.Namespaces[namespace]; !ok {
41+
logger.Warningf("tcp-services: namespace of service '%s/%s' not found", namespace, service)
42+
continue
43+
}
44+
svc, ok := k.Namespaces[namespace].Services[service]
45+
if !ok {
46+
logger.Warningf("tcp-services: service '%s/%s' not found", namespace, service)
47+
continue
4548
}
46-
switch svc.Status {
47-
case DELETED:
49+
// Delete Frontend
50+
frontendName := fmt.Sprintf("tcp-%s", port)
51+
if tcpSvc.Status == DELETED || svc.Status == DELETED {
4852
logger.Debugf("Deleting TCP frontend '%s'", frontendName)
4953
err = api.FrontendDelete(frontendName)
50-
logger.Panic(err)
51-
reload = true
52-
continue
53-
case MODIFIED:
54-
frontend, errFt := api.FrontendGet(frontendName)
5554
if err != nil {
56-
logger.Panic(errFt)
57-
continue
58-
}
59-
frontend.DefaultBackend = backendName
60-
if sslOption == "ssl" {
61-
logger.Error(api.FrontendEnableSSLOffload(frontend.Name, HAProxyFtCertDir, false))
55+
logger.Errorf("error deleting tcp frontend: %s", err)
6256
} else {
63-
logger.Error(api.FrontendDisableSSLOffload(frontend.Name))
64-
}
65-
logger.Debugf("Updating TCP frontend '%s'", frontendName)
66-
if err = api.FrontendEdit(frontend); err != nil {
67-
logger.Panic(err)
68-
continue
69-
}
70-
reload = true
71-
case ADDED:
72-
frontend := models.Frontend{
73-
Name: frontendName,
74-
Mode: "tcp",
75-
Tcplog: true,
76-
DefaultBackend: backendName,
77-
}
78-
logger.Debugf("Creating TCP frontend '%s'", frontendName)
79-
err = api.FrontendCreate(frontend)
80-
if err != nil {
81-
logger.Panic(err)
57+
reload = true
8258
}
83-
err = api.FrontendBindCreate(frontendName, models.Bind{
84-
Address: "0.0.0.0:" + port,
85-
Name: "v4",
86-
})
87-
logger.Panic(err)
88-
err = api.FrontendBindCreate(frontendName, models.Bind{
89-
Address: ":::" + port,
90-
Name: "v6",
91-
V4v6: true,
92-
})
93-
if err != nil {
94-
logger.Panic(err)
95-
}
96-
if sslOption == "ssl" {
97-
logger.Error(api.FrontendEnableSSLOffload(frontend.Name, HAProxyFtCertDir, false))
98-
}
99-
reload = true
59+
continue
10060
}
101-
102-
// Handle Backend
103-
var servicePort int64
104-
if servicePort, err = strconv.ParseInt(svcPort, 10, 64); err != nil {
61+
// Handle Route
62+
var portNbr int64
63+
if portNbr, err = strconv.ParseInt(svcPort, 10, 64); err != nil {
10564
logger.Error(err)
10665
continue
10766
}
@@ -112,16 +71,67 @@ func (t TCPHandler) Update(k store.K8s, cfg *Configuration, api api.HAProxyClien
11271
}
11372
path := &store.IngressPath{
11473
ServiceName: service,
115-
ServicePortInt: servicePort,
74+
ServicePortInt: portNbr,
11675
Status: svc.Status,
11776
}
118-
nsmmp := k.GetNamespace(namespace)
119-
logger.Error(cfg.IngressRoutes.AddRoute(&ingressRoute.Route{
120-
Namespace: nsmmp,
77+
route := &ingressRoute.Route{
78+
Namespace: k.GetNamespace(namespace),
12179
Ingress: ingress,
12280
Path: path,
12381
TCPService: true,
124-
}))
82+
}
83+
err = route.SetBackendName()
84+
if err != nil {
85+
logger.Error(err)
86+
continue
87+
}
88+
frontend, errGet := api.FrontendGet(frontendName)
89+
if errGet != nil {
90+
// Create Frontend
91+
frontend = models.Frontend{
92+
Name: frontendName,
93+
Mode: "tcp",
94+
Tcplog: true,
95+
DefaultBackend: route.BackendName,
96+
}
97+
var errors utils.Errors
98+
logger.Debugf("Creating TCP frontend '%s'", frontendName)
99+
errors.Add(api.FrontendCreate(frontend))
100+
errors.Add(api.FrontendBindCreate(frontendName, models.Bind{
101+
Address: "0.0.0.0:" + port,
102+
Name: "v4",
103+
}))
104+
errors.Add(api.FrontendBindCreate(frontendName, models.Bind{
105+
Address: ":::" + port,
106+
Name: "v6",
107+
V4v6: true,
108+
}))
109+
if sslOption == "ssl" {
110+
errors.Add(api.FrontendEnableSSLOffload(frontend.Name, HAProxyFtCertDir, false))
111+
}
112+
if errors.Result() != nil {
113+
logger.Errorf("error configuring tcp frontend: %s", err)
114+
continue
115+
}
116+
reload = true
117+
} else if svc.Status != EMPTY {
118+
// Update Frontend
119+
var errors utils.Errors
120+
logger.Debugf("Updating TCP frontend '%s'", frontendName)
121+
frontend.DefaultBackend = route.BackendName
122+
if sslOption == "ssl" {
123+
errors.Add(api.FrontendEnableSSLOffload(frontend.Name, HAProxyFtCertDir, false))
124+
} else {
125+
errors.Add(api.FrontendDisableSSLOffload(frontend.Name))
126+
}
127+
errors.Add(api.FrontendEdit(frontend))
128+
if errors.Result() != nil {
129+
logger.Errorf("error updating tcp frontend: %s", err)
130+
continue
131+
}
132+
reload = true
133+
}
134+
logger.Error(cfg.IngressRoutes.AddRoute(route))
125135
}
126136
return reload, err
127137
}

0 commit comments

Comments
 (0)