diff --git a/internal/dataplane/kong_client.go b/internal/dataplane/kong_client.go index 79218c5164..a71f5e94b5 100644 --- a/internal/dataplane/kong_client.go +++ b/internal/dataplane/kong_client.go @@ -428,17 +428,18 @@ func (c *KongClient) Update(ctx context.Context) error { func (c *KongClient) FetchLastGoodConfiguration(ctx context.Context) error { if c.lastValidKongState == nil { - var exists bool gatewayClients := c.clientsProvider.GatewayClients() c.logger.Debugf("sending configuration to %d gateway clients", len(gatewayClients)) type kongStateWithHash struct { kongState *kongstate.KongState hash string + rawState []byte } - kongStates, err := iter.MapErr(gatewayClients, func(client **adminapi.Client) (*kongStateWithHash, error) { - state, err := c.configGetter.GetCurrentKongState(ctx, (*client).AdminAPIClient()) + var goodKongState *kongStateWithHash + _, err := iter.MapErr(gatewayClients, func(client **adminapi.Client) (*kongStateWithHash, error) { + state, rawState, err := c.configGetter.GetCurrentKongState(ctx, (*client).AdminAPIClient()) if err != nil { return nil, err } @@ -452,40 +453,24 @@ func (c *KongClient) FetchLastGoodConfiguration(ctx context.Context) error { } state.Version = *version (*client).SetLastConfigSHA([]byte(status.ConfigurationHash)) + kongStateWithHash := &kongStateWithHash{ + kongState: state, + hash: status.ConfigurationHash, + rawState: rawState, + } if status.ConfigurationHash != sendconfig.WellKnownInitialHash { - exists = true + // get the first good one as the one to be used + goodKongState = kongStateWithHash } - return &kongStateWithHash{ - kongState: state, - hash: status.ConfigurationHash, - }, nil + return kongStateWithHash, nil }) if err != nil { return err } - // get the first good valid configuration... - var validKongState *kongstate.KongState - for _, ks := range kongStates { - if ks.hash != sendconfig.WellKnownInitialHash { - validKongState = ks.kongState - break - } - } - // then check that all the other configurations are coherent with the first good one. - var goodKongState *kongstate.KongState - for _, ks := range kongStates { - if ks.hash != sendconfig.WellKnownInitialHash { - if reflect.DeepEqual(*ks.kongState, *validKongState) { - goodKongState = ks.kongState - } else { - return errors.New("failed to resolve a unique last good configuration, different configurations coexist") - } - } - } - if exists { - c.lastValidKongState = goodKongState + if goodKongState != nil { + c.lastValidKongState = goodKongState.kongState } } return nil diff --git a/internal/dataplane/kong_client_test.go b/internal/dataplane/kong_client_test.go index ff30605407..411dc36e7a 100644 --- a/internal/dataplane/kong_client_test.go +++ b/internal/dataplane/kong_client_test.go @@ -255,8 +255,8 @@ func (m mockConfigurationGetter) HasConfigurationChanged( return m.hasConfigurationChanged, nil } -func (m mockConfigurationGetter) GetCurrentKongState(context.Context, sendconfig.ConfigClient) (*kongstate.KongState, error) { - return m.kongState, nil +func (m mockConfigurationGetter) GetCurrentKongState(context.Context, sendconfig.ConfigClient) (*kongstate.KongState, []byte, error) { + return m.kongState, nil, nil } func (m mockConfigurationGetter) GetCurrentStatus(context.Context, sendconfig.StatusClient) (*gokong.Status, error) { @@ -529,13 +529,16 @@ func TestKongClientUpdate_ConfigStatusIsAlwaysNotified(t *testing.T) { } } -func TestKongClientUpdate_PushLastValidConfig(t *testing.T) { +func TestKongClientUpdate_FetchAndPushLastValidConfig(t *testing.T) { var ( - ctx = context.Background() - testGatewayClient = mustSampleGatewayClient(t) + ctx = context.Background() + gatewayClients = []*adminapi.Client{ + mustSampleGatewayClient(t), + mustSampleGatewayClient(t), + } clientsProvider = mockGatewayClientsProvider{ - gatewayClients: []*adminapi.Client{testGatewayClient}, + gatewayClients: gatewayClients, } updateStrategyResolver = newMockUpdateStrategyResolver(t) @@ -617,7 +620,7 @@ func TestKongClientUpdate_PushLastValidConfig(t *testing.T) { lastValidConfighash: lastConfigHash, expectedLastKongState: lastKongState, gatewayFailure: true, - errorsSize: 2, + errorsSize: 3, }, { name: "no config fetched, success pushing", @@ -642,7 +645,9 @@ func TestKongClientUpdate_PushLastValidConfig(t *testing.T) { t.Run(tc.name, func(t *testing.T) { configGetter.kongState = tc.lastValidKongState configGetter.status.ConfigurationHash = tc.lastValidConfighash - updateStrategyResolver.returnErrorOnUpdate(testGatewayClient.BaseRootURL(), tc.gatewayFailure) + for _, client := range gatewayClients { + updateStrategyResolver.returnErrorOnUpdate(client.BaseRootURL(), tc.gatewayFailure) + } updateStrategyResolver.singleError = tc.singleError kongClient := setupTestKongClient(t, updateStrategyResolver, clientsProvider, configGetter, configBuilder) @@ -650,7 +655,7 @@ func TestKongClientUpdate_PushLastValidConfig(t *testing.T) { if tc.errorsSize > 0 { // check if the error is joined with other errors. When there are multiple errors, // they are separated by \n, hence we count the number of \n. - assert.Equal(t, strings.Count(err.Error(), "\n"), tc.errorsSize-1) + assert.Equal(t, tc.errorsSize, strings.Count(err.Error(), "\n")) } else { assert.NoError(t, err) } diff --git a/internal/dataplane/sendconfig/config_getter.go b/internal/dataplane/sendconfig/config_getter.go index 6690337e87..09db0927bc 100644 --- a/internal/dataplane/sendconfig/config_getter.go +++ b/internal/dataplane/sendconfig/config_getter.go @@ -25,7 +25,7 @@ type ConfigurationGetter interface { GetCurrentKongState( ctx context.Context, configClient ConfigClient, - ) (*kongstate.KongState, error) + ) (*kongstate.KongState, []byte, error) // GetCurrentStatus retrieves the currently loaded Kong status by using // the proxy's /status path. @@ -122,16 +122,16 @@ func (d *DefaultConfigurationGetter) HasConfigurationChanged( return false, nil } -func (d *DefaultConfigurationGetter) GetCurrentKongState(ctx context.Context, configClient ConfigClient) (*kongstate.KongState, error) { +func (d *DefaultConfigurationGetter) GetCurrentKongState(ctx context.Context, configClient ConfigClient) (*kongstate.KongState, []byte, error) { config, err := configClient.Config(ctx) if err != nil { - return nil, err + return nil, nil, err } state := &kongstate.KongState{} if err = yaml.Unmarshal(config, state); err != nil { - return nil, err + return nil, nil, err } - return state, nil + return state, config, err } func (d *DefaultConfigurationGetter) GetCurrentStatus(ctx context.Context, statusClient StatusClient) (*kong.Status, error) {