Skip to content

Commit e8fe260

Browse files
authored
fix: a failing endpoint shouldn't affect others (#2452) (#199)
1 parent a54da5a commit e8fe260

File tree

3 files changed

+66
-126
lines changed

3 files changed

+66
-126
lines changed

internal/provider/adc/adc.go

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@ package adc
2020
import (
2121
"context"
2222
"encoding/json"
23+
"fmt"
2324
"os"
2425
"slices"
26+
"strings"
2527
"sync"
2628
"time"
2729

@@ -286,6 +288,7 @@ func (d *adcClient) Start(ctx context.Context) error {
286288
initalSyncDelay := d.InitSyncDelay
287289
time.AfterFunc(initalSyncDelay, func() {
288290
if err := d.Sync(ctx); err != nil {
291+
log.Error(err)
289292
return
290293
}
291294
})
@@ -299,7 +302,7 @@ func (d *adcClient) Start(ctx context.Context) error {
299302
select {
300303
case <-ticker.C:
301304
if err := d.Sync(ctx); err != nil {
302-
log.Errorw("failed to sync resources", zap.Error(err))
305+
log.Error(err)
303306
}
304307
case <-ctx.Done():
305308
return nil
@@ -324,25 +327,32 @@ func (d *adcClient) Sync(ctx context.Context) error {
324327

325328
log.Debugw("syncing resources with multiple configs", zap.Any("configs", cfg))
326329

330+
var failedConfigs []string
327331
for name, config := range cfg {
328332
resources, err := d.store.GetResources(name)
329333
if err != nil {
330-
return err
334+
log.Errorw("failed to get resources from store", zap.String("name", name), zap.Error(err))
335+
failedConfigs = append(failedConfigs, name)
336+
continue
331337
}
332338
if resources == nil {
333339
continue
334340
}
335341

336-
err = d.sync(ctx, Task{
342+
if err := d.sync(ctx, Task{
337343
Name: name + "-sync",
338344
configs: []adcConfig{config},
339345
Resources: *resources,
340-
})
341-
if err != nil {
342-
return err
346+
}); err != nil {
347+
log.Errorw("failed to sync resources", zap.String("name", name), zap.Error(err))
348+
failedConfigs = append(failedConfigs, name)
343349
}
344350
}
345-
351+
if len(failedConfigs) > 0 {
352+
return fmt.Errorf("failed to sync %d configs: %s",
353+
len(failedConfigs),
354+
strings.Join(failedConfigs, ", "))
355+
}
346356
return nil
347357
}
348358

@@ -390,13 +400,16 @@ func (d *adcClient) sync(ctx context.Context, task Task) error {
390400

391401
args := BuildADCExecuteArgs(syncFilePath, task.Labels, task.ResourceTypes)
392402

393-
log.Debugw("syncing resources with multiple configs", zap.Any("configs", task.configs))
403+
var failedConfigs []string
394404
for _, config := range task.configs {
395405
if err := d.executor.Execute(ctx, d.BackendMode, config, args); err != nil {
396406
log.Errorw("failed to execute adc command", zap.Error(err), zap.Any("config", config))
397-
return err
407+
failedConfigs = append(failedConfigs, config.Name)
398408
}
399409
}
410+
if len(failedConfigs) > 0 {
411+
return fmt.Errorf("failed to execute adc command for configs: %s", strings.Join(failedConfigs, ", "))
412+
}
400413
return nil
401414
}
402415

internal/provider/adc/executor.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"context"
2323
"encoding/json"
2424
"errors"
25+
"fmt"
2526
"os"
2627
"os/exec"
2728
"strings"
@@ -50,11 +51,16 @@ func (e *DefaultADCExecutor) Execute(ctx context.Context, mode string, config ad
5051
}
5152

5253
func (e *DefaultADCExecutor) runADC(ctx context.Context, mode string, config adcConfig, args []string) error {
54+
var failedAddrs []string
5355
for _, addr := range config.ServerAddrs {
5456
if err := e.runForSingleServerWithTimeout(ctx, addr, mode, config, args); err != nil {
55-
return err
57+
log.Errorw("failed to run adc for server", zap.String("server", addr), zap.Error(err))
58+
failedAddrs = append(failedAddrs, addr)
5659
}
5760
}
61+
if len(failedAddrs) > 0 {
62+
return fmt.Errorf("failed to run adc for servers: [%s]", strings.Join(failedAddrs, ", "))
63+
}
5864
return nil
5965
}
6066

test/e2e/gatewayapi/gatewayproxy.go

Lines changed: 37 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package gatewayapi
1919

2020
import (
2121
"fmt"
22-
"net/http"
2322
"time"
2423

2524
. "github.com/onsi/ginkgo/v2"
@@ -103,64 +102,6 @@ spec:
103102
headers:
104103
X-Proxy-Test: "disabled"
105104
`
106-
var (
107-
gatewayProxyWithPluginMetadata0 = `
108-
apiVersion: apisix.apache.org/v1alpha1
109-
kind: GatewayProxy
110-
metadata:
111-
name: apisix-proxy-config
112-
spec:
113-
provider:
114-
type: ControlPlane
115-
controlPlane:
116-
endpoints:
117-
- %s
118-
auth:
119-
type: AdminKey
120-
adminKey:
121-
value: "%s"
122-
plugins:
123-
- name: error-page
124-
enabled: true
125-
config: {}
126-
pluginMetadata:
127-
error-page: {
128-
"enable": true,
129-
"error_404": {
130-
"body": "404 from plugin metadata",
131-
"content-type": "text/plain"
132-
}
133-
}
134-
`
135-
gatewayProxyWithPluginMetadata1 = `
136-
apiVersion: apisix.apache.org/v1alpha1
137-
kind: GatewayProxy
138-
metadata:
139-
name: apisix-proxy-config
140-
spec:
141-
provider:
142-
type: ControlPlane
143-
controlPlane:
144-
endpoints:
145-
- %s
146-
auth:
147-
type: AdminKey
148-
adminKey:
149-
value: "%s"
150-
plugins:
151-
- name: error-page
152-
enabled: true
153-
config: {}
154-
pluginMetadata:
155-
error-page: {
156-
"enable": false,
157-
"error_404": {
158-
"body": "404 from plugin metadata",
159-
"content-type": "text/plain"
160-
}
161-
}
162-
`
163-
)
164105

165106
var httpRouteForTest = `
166107
apiVersion: gateway.networking.k8s.io/v1
@@ -275,59 +216,48 @@ spec:
275216
})
276217
})
277218

278-
Context("Test Gateway with PluginMetadata", func() {
279-
var (
280-
err error
281-
)
282-
283-
PIt("Should work OK with error-page", func() {
284-
By("Update GatewayProxy with PluginMetadata")
285-
err = s.CreateResourceFromString(fmt.Sprintf(gatewayProxyWithPluginMetadata0, s.Deployer.GetAdminEndpoint(), s.AdminKey()))
286-
Expect(err).ShouldNot(HaveOccurred())
219+
Context("Test GatewayProxy with invalid endpoint", func() {
220+
var gatewayProxyWithInvalidEndpoint = `
221+
apiVersion: apisix.apache.org/v1alpha1
222+
kind: GatewayProxy
223+
metadata:
224+
name: apisix-proxy-config
225+
spec:
226+
provider:
227+
type: ControlPlane
228+
controlPlane:
229+
endpoints:
230+
- "http://invalid-endpoint:9180"
231+
- %s
232+
auth:
233+
type: AdminKey
234+
adminKey:
235+
value: "%s"
236+
`
237+
It("Should fail to apply GatewayProxy with invalid endpoint", func() {
238+
By("Update GatewayProxy with invalid endpoint")
239+
err := s.CreateResourceFromString(fmt.Sprintf(gatewayProxyWithInvalidEndpoint, s.Deployer.GetAdminEndpoint(), s.AdminKey()))
240+
Expect(err).NotTo(HaveOccurred(), "creating GatewayProxy with enabled plugin")
287241
time.Sleep(5 * time.Second)
288242

289-
By("Create HTTPRoute for Gateway with GatewayProxy")
243+
By("Create HTTPRoute")
290244
resourceApplied("HTTPRoute", "test-route", fmt.Sprintf(httpRouteForTest, "apisix"), 1)
291245

292-
time.Sleep(5 * time.Second)
293-
By("Check PluginMetadata working")
294-
s.NewAPISIXClient().
295-
GET("/not-found").
296-
WithHost("example.com").
297-
Expect().
298-
Status(http.StatusNotFound).
299-
Body().Contains("404 from plugin metadata")
300-
301-
By("Update GatewayProxy with PluginMetadata")
302-
err = s.CreateResourceFromString(fmt.Sprintf(gatewayProxyWithPluginMetadata1, s.Deployer.GetAdminEndpoint(), s.AdminKey()))
303-
Expect(err).ShouldNot(HaveOccurred())
304-
time.Sleep(5 * time.Second)
305-
306-
By("Check PluginMetadata working")
307-
s.NewAPISIXClient().
308-
GET("/not-found").
309-
WithHost("example.com").
310-
Expect().
311-
Status(http.StatusNotFound).
312-
Body().Contains(`{"error_msg":"404 Route Not Found"}`)
313-
314-
By("Delete GatewayProxy")
315-
err = s.DeleteResourceFromString(fmt.Sprintf(gatewayProxyWithPluginMetadata0, s.Deployer.GetAdminEndpoint(), s.AdminKey()))
316-
Expect(err).ShouldNot(HaveOccurred())
317-
time.Sleep(5 * time.Second)
246+
expectRequest := func() bool {
247+
resp := s.NewAPISIXClient().
248+
GET("/get").
249+
WithHost("example.com").
250+
Expect().Raw()
251+
return resp.StatusCode == 200 && resp.Header.Get("X-Proxy-Test") == ""
252+
}
318253

319-
By("Check PluginMetadata is not working")
320-
s.NewAPISIXClient().
321-
GET("/not-found").
322-
WithHost("example.com").
323-
Expect().
324-
Status(http.StatusNotFound).
325-
Body().Contains(`{"error_msg":"404 Route Not Found"}`)
254+
Eventually(expectRequest).WithTimeout(8 * time.Second).ProbeEvery(time.Second).Should(BeTrue())
326255
})
327256
})
328257

329-
var (
330-
gatewayProxyWithInvalidProviderType = `
258+
Context("Test GatewayProxy Provider Validation", func() {
259+
var (
260+
gatewayProxyWithInvalidProviderType = `
331261
apiVersion: apisix.apache.org/v1alpha1
332262
kind: GatewayProxy
333263
metadata:
@@ -336,7 +266,7 @@ spec:
336266
provider:
337267
type: "InvalidType"
338268
`
339-
gatewayProxyWithMissingControlPlane = `
269+
gatewayProxyWithMissingControlPlane = `
340270
apiVersion: apisix.apache.org/v1alpha1
341271
kind: GatewayProxy
342272
metadata:
@@ -345,7 +275,7 @@ spec:
345275
provider:
346276
type: "ControlPlane"
347277
`
348-
gatewayProxyWithValidProvider = `
278+
gatewayProxyWithValidProvider = `
349279
apiVersion: apisix.apache.org/v1alpha1
350280
kind: GatewayProxy
351281
metadata:
@@ -361,16 +291,7 @@ spec:
361291
adminKey:
362292
value: "test-key"
363293
`
364-
)
365-
366-
Context("Test GatewayProxy Provider Validation", func() {
367-
AfterEach(func() {
368-
By("Clean up GatewayProxy resources")
369-
_ = s.DeleteResourceFromString(gatewayProxyWithInvalidProviderType)
370-
_ = s.DeleteResourceFromString(gatewayProxyWithMissingControlPlane)
371-
_ = s.DeleteResourceFromString(gatewayProxyWithValidProvider)
372-
})
373-
294+
)
374295
It("Should reject invalid provider type", func() {
375296
By("Create GatewayProxy with invalid provider type")
376297
err := s.CreateResourceFromString(gatewayProxyWithInvalidProviderType)

0 commit comments

Comments
 (0)