Skip to content

Commit f46014f

Browse files
authored
fix(fallback): do not skip config update when gateways out of sync (#6271) (#6274)
(cherry picked from commit 3b547a9)
1 parent e11453f commit f46014f

File tree

7 files changed

+206
-84
lines changed

7 files changed

+206
-84
lines changed

CHANGELOG.md

+15-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Adding a new version? You'll need three changes:
77
* Add the diff link, like "[2.7.0]: https://github.com/kong/kubernetes-ingress-controller/compare/v1.2.2...v1.2.3".
88
This is all the way at the bottom. It's the thing we always forget.
99
--->
10+
- [3.2.2](#322)
1011
- [3.2.1](#321)
1112
- [3.2.0](#320)
1213
- [3.1.6](#316)
@@ -90,9 +91,21 @@ Adding a new version? You'll need three changes:
9091
- [0.0.5](#005)
9192
- [0.0.4 and prior](#004-and-prior)
9293

94+
## 3.2.2
95+
96+
> Release date: 2024-07-01
97+
98+
### Fixed
99+
100+
- Fixed an issue where new gateways were not being populated with the current configuration when
101+
`FallbackConfiguration` feature gate was turned on. Previously, configuration updates were skipped
102+
if the Kubernetes config cache did not change, leading to inconsistencies. Now, the system ensures
103+
that all gateways are populated with the latest configuration regardless of cache changes.
104+
[#6271](https://github.com/Kong/kubernetes-ingress-controller/pull/6271)
105+
93106
## 3.2.1
94107

95-
> Release date: 2024-06-28
108+
> Release date: 2024-06-28
96109
97110
### Fixed
98111

@@ -3559,6 +3572,7 @@ Please read the changelog and test in your environment.
35593572
- The initial versions were rapildy iterated to deliver
35603573
a working ingress controller.
35613574

3575+
[3.2.2]: https://github.com/kong/kubernetes-ingress-controller/compare/v3.2.1...v3.2.2
35623576
[3.2.1]: https://github.com/kong/kubernetes-ingress-controller/compare/v3.2.0...v3.2.1
35633577
[3.2.0]: https://github.com/kong/kubernetes-ingress-controller/compare/v3.1.6...v3.2.0
35643578
[3.1.6]: https://github.com/kong/kubernetes-ingress-controller/compare/v3.1.5...v3.1.6

internal/adminapi/client.go

+12
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/samber/lo"
1111
k8stypes "k8s.io/apimachinery/pkg/types"
1212

13+
"github.com/kong/kubernetes-ingress-controller/v3/internal/store"
1314
"github.com/kong/kubernetes-ingress-controller/v3/internal/util"
1415
"github.com/kong/kubernetes-ingress-controller/v3/internal/util/clock"
1516
)
@@ -25,6 +26,7 @@ type Client struct {
2526
isKonnect bool
2627
konnectControlPlane string
2728
lastConfigSHA []byte
29+
lastCacheStoresHash store.SnapshotHash
2830

2931
// podRef (optional) describes the Pod that the Client communicates with.
3032
podRef *k8stypes.NamespacedName
@@ -154,6 +156,16 @@ func (c *Client) KonnectControlPlane() string {
154156
return c.konnectControlPlane
155157
}
156158

159+
// SetLastCacheStoresHash overrides last cache stores hash.
160+
func (c *Client) SetLastCacheStoresHash(s store.SnapshotHash) {
161+
c.lastCacheStoresHash = s
162+
}
163+
164+
// LastCacheStoresHash returns a checksum of the last successful cache stores push.
165+
func (c *Client) LastCacheStoresHash() store.SnapshotHash {
166+
return c.lastCacheStoresHash
167+
}
168+
157169
// SetLastConfigSHA overrides last config SHA.
158170
func (c *Client) SetLastConfigSHA(s []byte) {
159171
c.lastConfigSHA = s

internal/dataplane/kong_client.go

+26-13
Original file line numberDiff line numberDiff line change
@@ -196,15 +196,15 @@ func NewKongClient(
196196
configChangeDetector sendconfig.ConfigurationChangeDetector,
197197
kongConfigFetcher configfetcher.LastValidConfigFetcher,
198198
kongConfigBuilder KongConfigBuilder,
199-
cacheStores store.CacheStores,
199+
cacheStores *store.CacheStores,
200200
fallbackConfigGenerator FallbackConfigGenerator,
201201
) (*KongClient, error) {
202202
c := &KongClient{
203203
logger: logger,
204204
requestTimeout: timeout,
205205
diagnostic: diagnostic,
206206
prometheusMetrics: metrics.NewCtrlFuncMetrics(),
207-
cache: &cacheStores,
207+
cache: cacheStores,
208208
kongConfig: kongConfig,
209209
eventRecorder: eventRecorder,
210210
dbmode: dbMode,
@@ -444,23 +444,30 @@ func (c *KongClient) Update(ctx context.Context) error {
444444
if c.kongConfig.FallbackConfiguration {
445445
var newSnapshotHash store.SnapshotHash
446446
var err error
447+
// Empty snapshot hash means that the cache hasn't changed since the last snapshot was taken. That optimization can be used
448+
// in main code path to avoid unnecessary processing. TODO: https://github.com/Kong/kubernetes-ingress-controller/issues/6095
447449
cacheSnapshot, newSnapshotHash, err = c.cache.TakeSnapshotIfChanged(c.lastProcessedSnapshotHash)
448450
if err != nil {
449451
return fmt.Errorf("failed to take snapshot of cache: %w", err)
450452
}
451-
// Empty snapshot hash means that the cache hasn't changed since the last snapshot was taken. That optimization can be used
452-
// in main code path to avoid unnecessary processing. TODO: https://github.com/Kong/kubernetes-ingress-controller/issues/6095
453-
// TODO: We should short-circuit here only if all the Gateways were successfully synced with the current configuration.
454-
// https://github.com/Kong/kubernetes-ingress-controller/issues/6219
455-
if newSnapshotHash == store.SnapshotHashEmpty {
453+
hasNewSnapshotToBeProcessed := newSnapshotHash != store.SnapshotHashEmpty
454+
if !hasNewSnapshotToBeProcessed {
456455
c.prometheusMetrics.RecordProcessedConfigSnapshotCacheHit()
457-
c.logger.V(util.DebugLevel).Info("No configuration change; pushing config to gateway is not necessary, skipping")
458-
return nil
456+
} else {
457+
c.prometheusMetrics.RecordProcessedConfigSnapshotCacheMiss()
458+
}
459+
if hasNewSnapshotToBeProcessed {
460+
c.logger.V(util.DebugLevel).Info("New configuration snapshot detected", "hash", newSnapshotHash)
461+
c.lastProcessedSnapshotHash = newSnapshotHash
462+
c.kongConfigBuilder.UpdateCache(cacheSnapshot)
459463
}
460464

461-
c.prometheusMetrics.RecordProcessedConfigSnapshotCacheMiss()
462-
c.lastProcessedSnapshotHash = newSnapshotHash
463-
c.kongConfigBuilder.UpdateCache(cacheSnapshot)
465+
if allGatewaysAreInSync := lo.EveryBy(c.clientsProvider.GatewayClientsToConfigure(), func(cl *adminapi.Client) bool {
466+
return cl.LastCacheStoresHash() == c.lastProcessedSnapshotHash
467+
}); allGatewaysAreInSync {
468+
c.logger.V(util.DebugLevel).Info("All gateways are in sync; pushing config is not necessary, skipping")
469+
return nil
470+
}
464471
}
465472

466473
c.logger.V(util.DebugLevel).Info("Parsing kubernetes objects into data-plane configuration")
@@ -700,6 +707,12 @@ func (c *KongClient) sendOutToGatewayClients(
700707
len(gatewayClients) > 1 {
701708
for _, client := range gatewayClients {
702709
client.SetLastConfigSHA([]byte(shas[0]))
710+
711+
// If the last processed snapshot hash is not empty, we should set it to the clients as well.
712+
// It can be empty when FallbackConfiguration feature gate is off.
713+
if c.lastProcessedSnapshotHash != "" {
714+
client.SetLastCacheStoresHash(c.lastProcessedSnapshotHash)
715+
}
703716
}
704717
}
705718

@@ -840,7 +853,7 @@ func (c *KongClient) sendToClient(
840853
sendDiagnostic(diagnostics.DumpMeta{Failed: false, Hash: string(newConfigSHA)}, nil) // No error occurred.
841854
// update the lastConfigSHA with the new updated checksum
842855
client.SetLastConfigSHA(newConfigSHA)
843-
856+
client.SetLastCacheStoresHash(c.lastProcessedSnapshotHash)
844857
return string(newConfigSHA), nil
845858
}
846859

internal/dataplane/kong_client_golden_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ func runKongClientGoldenTest(t *testing.T, tc kongClientGoldenTestCase) {
307307
sendconfig.NewDefaultConfigurationChangeDetector(logger),
308308
lastValidConfigFetcher,
309309
p,
310-
cacheStores,
310+
&cacheStores,
311311
fallbackConfigGenerator,
312312
)
313313
require.NoError(t, err)

0 commit comments

Comments
 (0)