diff --git a/provider/webhook/webhook.go b/provider/webhook/webhook.go index ca6fea1998..10a0167470 100644 --- a/provider/webhook/webhook.go +++ b/provider/webhook/webhook.go @@ -269,6 +269,16 @@ func (p WebhookProvider) ApplyChanges(ctx context.Context, changes *plan.Changes // This method returns an empty slice in case there is a technical error on the provider's side so that no endpoints will be considered. func (p WebhookProvider) AdjustEndpoints(e []*endpoint.Endpoint) ([]*endpoint.Endpoint, error) { adjustEndpointsRequestsGauge.Gauge.Inc() + + // refObject is not serialized to JSON (tagged json:"-"), so we must + // preserve it across the webhook round-trip to keep event emission working. + refObjects := make(map[endpoint.EndpointKey]*endpoint.ObjectRef, len(e)) + for _, ep := range e { + if ep.RefObject() != nil { + refObjects[ep.Key()] = ep.RefObject() + } + } + var endpoints []*endpoint.Endpoint u, err := url.JoinPath(p.remoteServerURL.String(), webhookapi.UrlAdjustEndpoints) if err != nil { @@ -320,6 +330,12 @@ func (p WebhookProvider) AdjustEndpoints(e []*endpoint.Endpoint) ([]*endpoint.En return nil, err } + for _, ep := range endpoints { + if ref, ok := refObjects[ep.Key()]; ok { + ep.WithRefObject(ref) + } + } + return endpoints, nil } diff --git a/provider/webhook/webhook_test.go b/provider/webhook/webhook_test.go index 7f9e30785c..ad6bc42b1b 100644 --- a/provider/webhook/webhook_test.go +++ b/provider/webhook/webhook_test.go @@ -31,6 +31,7 @@ import ( "sigs.k8s.io/external-dns/endpoint" "sigs.k8s.io/external-dns/internal/testutils" + "sigs.k8s.io/external-dns/pkg/events" extdnshttp "sigs.k8s.io/external-dns/pkg/http" "sigs.k8s.io/external-dns/pkg/metrics" "sigs.k8s.io/external-dns/plan" @@ -355,6 +356,46 @@ func TestAdjustEndpoints(t *testing.T) { }}, adjustedEndpoints) } +func TestAdjustEndpoints_PreservesRefObject(t *testing.T) { + svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/" { + w.Header().Set(webhookapi.ContentTypeHeader, webhookapi.MediaTypeFormatAndVersion) + w.Write([]byte(`{}`)) + return + } + assert.Equal(t, webhookapi.UrlAdjustEndpoints, r.URL.Path) + + var endpoints []*endpoint.Endpoint + defer r.Body.Close() + b, err := io.ReadAll(r.Body) + if err != nil { + t.Fatal(err) + } + err = json.Unmarshal(b, &endpoints) + if err != nil { + t.Fatal(err) + } + + j, _ := json.Marshal(endpoints) + w.Write(j) + })) + defer svr.Close() + + p, err := newProvider(t.Context(), svr.URL, testReadTimeout, testWriteTimeout) + require.NoError(t, err) + + ref := events.NewObjectReferenceFromParts("Service", "v1", "default", "my-svc", "", "") + endpoints := []*endpoint.Endpoint{ + endpoint.NewEndpoint("test.example.com", "A", "1.2.3.4").WithRefObject(ref), + } + + adjusted, err := p.AdjustEndpoints(endpoints) + require.NoError(t, err) + require.Len(t, adjusted, 1) + require.NotNil(t, adjusted[0].RefObject(), "refObject should be preserved across webhook round-trip") + assert.Equal(t, ref, adjusted[0].RefObject()) +} + func TestAdjustendpointsWithError(t *testing.T) { svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/" {