Skip to content

Commit 6e322c4

Browse files
committed
BUG/MINOR: fix k8s resync for all objects expect endpoints, endpointslices.
Endpoint and endpointslices fix is done in a previous commit. With informers, resync are sent as Update, not Create. We were doing nothing on an Update on a resync. If an event was skipped for any reason, we were never resyncing.
1 parent 0ce0bec commit 6e322c4

File tree

7 files changed

+401
-60
lines changed

7 files changed

+401
-60
lines changed
Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
// Copyright 2019 HAProxy Technologies LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package podmaxconn
16+
17+
import (
18+
"github.com/haproxytech/kubernetes-ingress/pkg/k8s"
19+
"github.com/haproxytech/kubernetes-ingress/pkg/store"
20+
networkingv1 "k8s.io/api/networking/v1"
21+
)
22+
23+
func (suite *PodMaxConnSuite) TestPodMaxConnConfigMap() {
24+
suite.StartController()
25+
cm := suite.setupTest()
26+
27+
///////////////////////////////////////
28+
// pod-maxconn setup in:
29+
// - configmap only
30+
cm.Status = store.MODIFIED
31+
cm.Annotations["pod-maxconn"] = "128"
32+
svc := newAppSvc()
33+
ing := newAppIngress()
34+
events := []k8s.SyncDataEvent{
35+
{SyncType: k8s.CONFIGMAP, Namespace: configMapNamespace, Name: configMapName, Data: cm},
36+
{SyncType: k8s.POD, Namespace: configMapName, Name: "ic1", Data: store.PodEvent{
37+
Status: store.ADDED,
38+
Name: "ic1",
39+
}},
40+
{SyncType: k8s.POD, Namespace: configMapName, Name: "ic2", Data: store.PodEvent{
41+
Status: store.ADDED,
42+
Name: "ic2",
43+
}},
44+
{SyncType: k8s.SERVICE, Namespace: appNs, Name: serviceName, Data: svc},
45+
{SyncType: k8s.INGRESS, Namespace: appNs, Name: ingressName, Data: ing},
46+
}
47+
suite.fixture(events...)
48+
// Expected occurrences of "default-server check maxconn 64"
49+
// 64 = 128 / 2 instances of IC
50+
// 1- backend haproxy-controller_default-local-service_http
51+
// 1- backend appNs_appSvcName_https
52+
suite.ExpectHaproxyConfigContains("default-server check maxconn 64", 2)
53+
54+
suite.StopController()
55+
}
56+
57+
func (suite *PodMaxConnSuite) TestPodMaxConnConfigMapMisc() {
58+
suite.StartController()
59+
cm := suite.setupTest()
60+
61+
///////////////////////////////////////
62+
// pod-maxconn setup in:
63+
// - configmap only
64+
cm.Status = store.MODIFIED
65+
cm.Annotations["pod-maxconn"] = "128"
66+
svc := newAppSvc()
67+
ing := newAppIngress()
68+
events := []k8s.SyncDataEvent{
69+
{SyncType: k8s.CONFIGMAP, Namespace: configMapNamespace, Name: configMapName, Data: cm},
70+
{SyncType: k8s.POD, Namespace: configMapName, Name: "ic1", Data: store.PodEvent{
71+
Status: store.ADDED,
72+
Name: "ic1",
73+
}},
74+
{SyncType: k8s.POD, Namespace: configMapName, Name: "ic2", Data: store.PodEvent{
75+
Status: store.ADDED,
76+
Name: "ic2",
77+
}},
78+
{SyncType: k8s.SERVICE, Namespace: appNs, Name: serviceName, Data: svc},
79+
{SyncType: k8s.INGRESS, Namespace: appNs, Name: ingressName, Data: ing},
80+
}
81+
suite.fixture(events...)
82+
// Expected occurrences of "default-server check maxconn 64"
83+
// 64 = 128 / 2 instances of IC
84+
// 1- backend haproxy-controller_default-local-service_http
85+
// 1- backend appNs_appSvcName_https
86+
suite.ExpectHaproxyConfigContains("default-server check maxconn 64", 2)
87+
88+
// -------------------------------------
89+
// Resend ADDED => should change nothing
90+
events = []k8s.SyncDataEvent{
91+
{SyncType: k8s.POD, Namespace: configMapName, Name: "ic1", Data: store.PodEvent{
92+
Status: store.ADDED,
93+
Name: "ic1",
94+
}},
95+
{SyncType: k8s.POD, Namespace: configMapName, Name: "ic2", Data: store.PodEvent{
96+
Status: store.ADDED,
97+
Name: "ic2",
98+
}},
99+
}
100+
suite.fixture(events...)
101+
// Expected occurrences of "default-server check maxconn 64"
102+
// 64 = 128 / 2 instances of IC
103+
// 1- backend haproxy-controller_default-local-service_http
104+
// 1- backend appNs_appSvcName_https
105+
suite.ExpectHaproxyConfigContains("default-server check maxconn 64", 2)
106+
107+
// -------------------------------------
108+
// SEND MODIFIED => should change nothing
109+
events = []k8s.SyncDataEvent{
110+
{SyncType: k8s.POD, Namespace: configMapName, Name: "ic1", Data: store.PodEvent{
111+
Status: store.MODIFIED,
112+
Name: "ic1",
113+
}},
114+
{SyncType: k8s.POD, Namespace: configMapName, Name: "ic2", Data: store.PodEvent{
115+
Status: store.MODIFIED,
116+
Name: "ic2",
117+
}},
118+
}
119+
suite.fixture(events...)
120+
// Expected occurrences of "default-server check maxconn 64"
121+
// 64 = 128 / 2 instances of IC
122+
// 1- backend haproxy-controller_default-local-service_http
123+
// 1- backend appNs_appSvcName_https
124+
suite.ExpectHaproxyConfigContains("default-server check maxconn 64", 2)
125+
126+
// --------------------------------------------------
127+
// Send MODIFIED on a non-existing POD -> should increment
128+
events = []k8s.SyncDataEvent{
129+
{SyncType: k8s.POD, Namespace: configMapName, Name: "ic3", Data: store.PodEvent{
130+
Status: store.MODIFIED,
131+
Name: "ic3",
132+
}},
133+
{SyncType: k8s.POD, Namespace: configMapName, Name: "ic4", Data: store.PodEvent{
134+
Status: store.MODIFIED,
135+
Name: "ic4",
136+
}},
137+
}
138+
suite.fixture(events...)
139+
// Expected occurrences of "default-server check maxconn 32" (divided by 4)
140+
// 64 = 128 / 2 instances of IC
141+
// 1- backend haproxy-controller_default-local-service_http
142+
// 1- backend appNs_appSvcName_https
143+
suite.ExpectHaproxyConfigContains("default-server check maxconn 32", 2)
144+
145+
suite.StopController()
146+
}
147+
148+
func (suite *PodMaxConnSuite) TestPodMaxConnService() {
149+
suite.StartController()
150+
cm := suite.setupTest()
151+
152+
///////////////////////////////////////
153+
// pod-maxconn setup in:
154+
// - configmap (128)
155+
// - ingress (126)
156+
// - app svc (124) (appNs_appSvcName_https)
157+
cm.Status = store.MODIFIED
158+
cm.Annotations["pod-maxconn"] = "128"
159+
ing := newAppIngress()
160+
ing.Annotations["pod-maxconn"] = "126"
161+
svc := newAppSvc()
162+
svc.Annotations["pod-maxconn"] = "124"
163+
164+
events := []k8s.SyncDataEvent{
165+
{SyncType: k8s.CONFIGMAP, Namespace: configMapNamespace, Name: configMapName, Data: cm},
166+
{SyncType: k8s.POD, Namespace: configMapName, Name: "ic1", Data: store.PodEvent{
167+
Status: store.ADDED,
168+
Name: "ic1",
169+
}},
170+
{SyncType: k8s.POD, Namespace: configMapName, Name: "ic2", Data: store.PodEvent{
171+
Status: store.ADDED,
172+
Name: "ic2",
173+
}},
174+
{SyncType: k8s.SERVICE, Namespace: appNs, Name: serviceName, Data: svc},
175+
{SyncType: k8s.INGRESS, Namespace: appNs, Name: ingressName, Data: ing},
176+
}
177+
suite.fixture(events...)
178+
// -- Expected occurrences of "default-server check maxconn 64" #1 (from configmap)
179+
// backend haproxy-controller_default-local-service_http
180+
// -- Expected occurrences of "default-server check maxconn 62": #1 (from service)
181+
// backend appNs_appSvcName_https
182+
suite.ExpectHaproxyConfigContains("default-server check maxconn 64", 1)
183+
suite.ExpectHaproxyConfigContains("default-server check maxconn 62", 1)
184+
suite.ExpectHaproxyConfigContains("default-server check maxconn 63", 0)
185+
186+
suite.StopController()
187+
}
188+
189+
func (suite *PodMaxConnSuite) TestPodMaxConnIngress() {
190+
suite.StartController()
191+
cm := suite.setupTest()
192+
193+
// pod-maxconn setup in:
194+
// timeout server setup in:
195+
// - configmap (77000)
196+
// - ingress (76000)
197+
cm.Status = store.MODIFIED
198+
cm.Annotations["pod-maxconn"] = "128"
199+
ing := newAppIngress()
200+
ing.Annotations["pod-maxconn"] = "126"
201+
svc := newAppSvc()
202+
203+
events := []k8s.SyncDataEvent{
204+
{SyncType: k8s.CONFIGMAP, Namespace: configMapNamespace, Name: configMapName, Data: cm},
205+
{SyncType: k8s.POD, Namespace: configMapName, Name: "ic1", Data: store.PodEvent{
206+
Status: store.ADDED,
207+
Name: "ic1",
208+
}},
209+
{SyncType: k8s.POD, Namespace: configMapName, Name: "ic2", Data: store.PodEvent{
210+
Status: store.ADDED,
211+
Name: "ic2",
212+
}},
213+
{SyncType: k8s.SERVICE, Namespace: appNs, Name: serviceName, Data: svc},
214+
{SyncType: k8s.INGRESS, Namespace: appNs, Name: ingressName, Data: ing},
215+
}
216+
suite.fixture(events...)
217+
// -- Expected occurrences of "default-server check maxconn 64" #1 (from configmap)
218+
// backend haproxy-controller_default-local-service_http
219+
// -- Expected occurrences of "default-server check maxconn 62": #1 (from service)
220+
// backend appNs_appSvcName_https
221+
suite.ExpectHaproxyConfigContains("default-server check maxconn 64", 1)
222+
suite.ExpectHaproxyConfigContains("default-server check maxconn 62", 0)
223+
suite.ExpectHaproxyConfigContains("default-server check maxconn 63", 1)
224+
225+
suite.StopController()
226+
}
227+
228+
func newAppSvc() *store.Service {
229+
return &store.Service{
230+
Annotations: map[string]string{},
231+
Name: serviceName,
232+
Namespace: appNs,
233+
Ports: []store.ServicePort{
234+
{
235+
Name: "https",
236+
Protocol: "TCP",
237+
Port: 443,
238+
Status: store.ADDED,
239+
},
240+
},
241+
Status: store.ADDED,
242+
}
243+
}
244+
245+
func newAppIngress() *store.Ingress {
246+
return &store.Ingress{
247+
IngressCore: store.IngressCore{
248+
APIVersion: store.NETWORKINGV1,
249+
Name: ingressName,
250+
Namespace: appNs,
251+
Annotations: map[string]string{},
252+
Rules: map[string]*store.IngressRule{
253+
"": {
254+
Paths: map[string]*store.IngressPath{
255+
string(networkingv1.PathTypePrefix) + "-/": {
256+
Path: "/",
257+
PathTypeMatch: string(networkingv1.PathTypePrefix),
258+
SvcNamespace: appNs,
259+
SvcPortString: "https",
260+
SvcName: serviceName,
261+
},
262+
},
263+
},
264+
},
265+
},
266+
Status: store.ADDED,
267+
}
268+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// Copyright 2023 HAProxy Technologies LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package podmaxconn
16+
17+
import (
18+
"testing"
19+
20+
"github.com/haproxytech/kubernetes-ingress/deploy/tests/integration"
21+
"github.com/haproxytech/kubernetes-ingress/pkg/k8s"
22+
"github.com/haproxytech/kubernetes-ingress/pkg/store"
23+
"github.com/stretchr/testify/suite"
24+
)
25+
26+
var (
27+
appNs = "appNs"
28+
serviceName = "appSvcName"
29+
ingressName = "appIngName"
30+
configMapNamespace = "haproxy-controller"
31+
configMapName = "haproxy-kubernetes-ingress"
32+
)
33+
34+
type PodMaxConnSuite struct {
35+
integration.BaseSuite
36+
}
37+
38+
func TestPodMaxConn(t *testing.T) {
39+
t.Parallel()
40+
suite.Run(t, new(PodMaxConnSuite))
41+
}
42+
43+
func (suite *PodMaxConnSuite) BeforeTest(suiteName, testName string) {
44+
suite.BaseSuite.BeforeTest(suiteName, testName)
45+
// Add any needed update to the controller setting
46+
// by updating suite.TestControllers[suite.T().Name()].XXXXX
47+
testController := suite.TestControllers[suite.T().Name()]
48+
testController.OSArgs.ConfigMap.Name = configMapName
49+
testController.OSArgs.ConfigMap.Namespace = configMapNamespace
50+
}
51+
52+
func newConfigMap() *store.ConfigMap {
53+
return &store.ConfigMap{
54+
Annotations: map[string]string{},
55+
Namespace: configMapNamespace,
56+
Name: configMapName,
57+
Status: store.ADDED,
58+
}
59+
}
60+
61+
func (suite *PodMaxConnSuite) setupTest() *store.ConfigMap {
62+
testController := suite.TestControllers[suite.T().Name()]
63+
64+
ns := store.Namespace{Name: appNs, Status: store.ADDED}
65+
cm := newConfigMap()
66+
testController.EventChan <- k8s.SyncDataEvent{SyncType: k8s.NAMESPACE, Namespace: ns.Name, Data: &ns}
67+
testController.EventChan <- k8s.SyncDataEvent{
68+
SyncType: k8s.CONFIGMAP, Namespace: configMapNamespace, Name: configMapName, Data: newConfigMap(),
69+
}
70+
testController.EventChan <- k8s.SyncDataEvent{SyncType: k8s.COMMAND}
71+
controllerHasWorked := make(chan struct{})
72+
testController.EventChan <- k8s.SyncDataEvent{SyncType: k8s.COMMAND, EventProcessed: controllerHasWorked}
73+
<-controllerHasWorked
74+
return cm
75+
}
76+
77+
func (suite *PodMaxConnSuite) fixture(events ...k8s.SyncDataEvent) {
78+
testController := suite.TestControllers[suite.T().Name()]
79+
80+
// Now sending store events for test setup
81+
for _, e := range events {
82+
testController.EventChan <- e
83+
}
84+
testController.EventChan <- k8s.SyncDataEvent{SyncType: k8s.COMMAND}
85+
controllerHasWorked := make(chan struct{})
86+
testController.EventChan <- k8s.SyncDataEvent{SyncType: k8s.COMMAND, EventProcessed: controllerHasWorked}
87+
<-controllerHasWorked
88+
}

pkg/annotations/service/maxconn.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ func (a *Maxconn) Process(k store.K8s, annotations ...map[string]string) error {
3535
return err
3636
}
3737
// adjust backend maxconn when using multiple HAProxy Instances
38-
if k.NbrHAProxyInst != 0 {
39-
v /= k.NbrHAProxyInst
38+
if len(k.HaProxyPods) != 0 {
39+
v /= int64(len(k.HaProxyPods))
4040
}
4141
if a.backend.DefaultServer == nil {
4242
a.backend.DefaultServer = &models.DefaultServer{}

0 commit comments

Comments
 (0)