Skip to content

Commit 42a1646

Browse files
committed
feat: support retry for full synchronization
1 parent 133ed58 commit 42a1646

3 files changed

Lines changed: 208 additions & 2 deletions

File tree

internal/provider/api7ee/provider.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,18 @@ import (
3939
"github.com/apache/apisix-ingress-controller/internal/controller/status"
4040
"github.com/apache/apisix-ingress-controller/internal/manager/readiness"
4141
"github.com/apache/apisix-ingress-controller/internal/provider"
42+
"github.com/apache/apisix-ingress-controller/internal/provider/common"
4243
"github.com/apache/apisix-ingress-controller/internal/types"
4344
"github.com/apache/apisix-ingress-controller/internal/utils"
4445
pkgutils "github.com/apache/apisix-ingress-controller/pkg/utils"
4546
)
4647

47-
const ProviderTypeAPI7EE = "api7ee"
48+
const (
49+
ProviderTypeAPI7EE = "api7ee"
50+
51+
RetryBaseDelay = 1 * time.Second
52+
RetryMaxDelay = 1000 * time.Second
53+
)
4854

4955
type api7eeProvider struct {
5056
translator *translator.Translator
@@ -252,6 +258,9 @@ func (d *api7eeProvider) Start(ctx context.Context) error {
252258
}
253259
ticker := time.NewTicker(d.SyncPeriod)
254260
defer ticker.Stop()
261+
262+
retrier := common.NewRetrier(common.NewExponentialBackoff(RetryBaseDelay, RetryMaxDelay))
263+
255264
for {
256265
synced := false
257266
select {
@@ -267,6 +276,13 @@ func (d *api7eeProvider) Start(ctx context.Context) error {
267276
d.log.Error(err, "failed to sync for startup")
268277
}
269278
}
279+
280+
if err := d.sync(ctx); err != nil {
281+
d.log.Error(err, "failed to sync")
282+
retrier.Next()
283+
} else {
284+
retrier.Reset()
285+
}
270286
}
271287
}
272288

test/e2e/api7/gatewayproxy.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
// specific language governing permissions and limitations
1616
// under the License.
1717

18-
package gatewayapi
18+
package api7
1919

2020
import (
2121
"fmt"

test/e2e/api7/route.go

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package api7
19+
20+
import (
21+
"fmt"
22+
"time"
23+
24+
. "github.com/onsi/ginkgo/v2"
25+
. "github.com/onsi/gomega"
26+
corev1 "k8s.io/api/core/v1"
27+
"sigs.k8s.io/yaml"
28+
29+
"github.com/apache/apisix-ingress-controller/test/e2e/framework"
30+
"github.com/apache/apisix-ingress-controller/test/e2e/scaffold"
31+
)
32+
33+
var _ = Describe("Test apisix.apache.org/v2 Status", Label("apisix.apache.org", "v2", "apisixroute"), func() {
34+
var (
35+
s = scaffold.NewScaffold(scaffold.Options{
36+
// for triggering the sync
37+
SyncPeriod: 3 * time.Second,
38+
})
39+
applier = framework.NewApplier(s.GinkgoT, s.K8sClient, s.CreateResourceFromString)
40+
)
41+
42+
Context("Test ApisixRoute Sync Status", func() {
43+
BeforeEach(func() {
44+
By("create GatewayProxy")
45+
err := s.CreateResourceFromString(s.GetGatewayProxySpec())
46+
Expect(err).NotTo(HaveOccurred(), "creating GatewayProxy")
47+
time.Sleep(5 * time.Second)
48+
49+
By("create IngressClass")
50+
err = s.CreateResourceFromStringWithNamespace(s.GetIngressClassYaml(), "")
51+
Expect(err).NotTo(HaveOccurred(), "creating IngressClass")
52+
time.Sleep(5 * time.Second)
53+
})
54+
const ar = `
55+
apiVersion: apisix.apache.org/v2
56+
kind: ApisixRoute
57+
metadata:
58+
name: default
59+
namespace: %s
60+
spec:
61+
ingressClassName: %s
62+
http:
63+
- name: rule0
64+
match:
65+
hosts:
66+
- httpbin
67+
paths:
68+
- /*
69+
backends:
70+
- serviceName: httpbin-service-e2e-test
71+
servicePort: 80
72+
`
73+
const arWithInvalidPlugin = `
74+
apiVersion: apisix.apache.org/v2
75+
kind: ApisixRoute
76+
metadata:
77+
name: default
78+
namespace: %s
79+
spec:
80+
ingressClassName: %s
81+
http:
82+
- name: rule0
83+
match:
84+
hosts:
85+
- httpbin
86+
paths:
87+
- /*
88+
backends:
89+
- serviceName: httpbin-service-e2e-test
90+
servicePort: 80
91+
plugins:
92+
- name: non-existent-plugin
93+
enable: true
94+
`
95+
const arWithInvalidIngressClass = `
96+
apiVersion: apisix.apache.org/v2
97+
kind: ApisixRoute
98+
metadata:
99+
name: ar-with-invalid-ingressclass
100+
spec:
101+
ingressClassName: ar-with-invalid-ingressclass
102+
http:
103+
- name: rule0
104+
match:
105+
hosts:
106+
- httpbin
107+
paths:
108+
- /*
109+
backends:
110+
- serviceName: httpbin-service-e2e-test
111+
servicePort: 80
112+
`
113+
114+
It("dataplane unavailable", func() {
115+
s.Deployer.ScaleIngress(0)
116+
By("apply ApisixRoute")
117+
s.CreateResourceFromString(fmt.Sprintf(ar, s.Namespace(), s.Namespace()))
118+
119+
By("get yaml from service")
120+
serviceYaml, err := s.GetOutputFromString("svc", framework.ProviderType, "-o", "yaml")
121+
Expect(err).NotTo(HaveOccurred(), "getting service yaml")
122+
By("update service to type ExternalName with invalid host")
123+
var k8sservice corev1.Service
124+
err = yaml.Unmarshal([]byte(serviceYaml), &k8sservice)
125+
Expect(err).NotTo(HaveOccurred(), "unmarshalling service")
126+
oldSpec := k8sservice.Spec
127+
k8sservice.Spec = corev1.ServiceSpec{
128+
Type: corev1.ServiceTypeExternalName,
129+
ExternalName: "invalid.host",
130+
}
131+
newServiceYaml, err := yaml.Marshal(k8sservice)
132+
Expect(err).NotTo(HaveOccurred(), "marshalling service")
133+
err = s.CreateResourceFromString(string(newServiceYaml))
134+
Expect(err).NotTo(HaveOccurred(), "creating service")
135+
136+
s.Deployer.ScaleIngress(1)
137+
138+
By("check route in APISIX")
139+
s.RequestAssert(&scaffold.RequestAssert{
140+
Method: "GET",
141+
Path: "/get",
142+
Headers: map[string]string{"Host": "httpbin"},
143+
Check: scaffold.WithExpectedStatus(404),
144+
})
145+
146+
By("check ApisixRoute status")
147+
s.RetryAssertion(func() string {
148+
output, _ := s.GetOutputFromString("ar", "default", "-o", "yaml", "-n", s.Namespace())
149+
return output
150+
}).WithTimeout(60 * time.Second).
151+
Should(
152+
And(
153+
ContainSubstring(`status: "False"`),
154+
ContainSubstring(`reason: SyncFailed`),
155+
),
156+
)
157+
158+
By("update service to original spec")
159+
serviceYaml, err = s.GetOutputFromString("svc", framework.ProviderType, "-o", "yaml")
160+
Expect(err).NotTo(HaveOccurred(), "getting service yaml")
161+
err = yaml.Unmarshal([]byte(serviceYaml), &k8sservice)
162+
Expect(err).NotTo(HaveOccurred(), "unmarshalling service")
163+
k8sservice.Spec = oldSpec
164+
newServiceYaml, err = yaml.Marshal(k8sservice)
165+
Expect(err).NotTo(HaveOccurred(), "marshalling service")
166+
err = s.CreateResourceFromString(string(newServiceYaml))
167+
Expect(err).NotTo(HaveOccurred(), "creating service")
168+
169+
By("check ApisixRoute status after scaling up")
170+
s.RetryAssertion(func() string {
171+
output, _ := s.GetOutputFromString("ar", "default", "-o", "yaml", "-n", s.Namespace())
172+
return output
173+
}).WithTimeout(60 * time.Second).
174+
Should(
175+
And(
176+
ContainSubstring(`status: "True"`),
177+
ContainSubstring(`reason: Accepted`),
178+
),
179+
)
180+
181+
By("check route in APISIX")
182+
s.RequestAssert(&scaffold.RequestAssert{
183+
Method: "GET",
184+
Path: "/get",
185+
Host: "httpbin",
186+
Check: scaffold.WithExpectedStatus(200),
187+
})
188+
})
189+
})
190+
})

0 commit comments

Comments
 (0)