diff --git a/docs/tutorials/webhook-provider.md b/docs/tutorials/webhook-provider.md index dd07e727f..c956ce325 100644 --- a/docs/tutorials/webhook-provider.md +++ b/docs/tutorials/webhook-provider.md @@ -31,11 +31,16 @@ The default recommended port is 8888, and should listen only on localhost (ie: o **NOTE**: only `5xx` responses will be retried and only `20x` will be considered as successful. All status codes different from those will be considered a failure on ExternalDNS's side. - ## Metrics support The metrics should listen ":8080" on `/metrics` following [Open Metrics](https://github.com/OpenObservability/OpenMetrics) format. +## Custom Annotations + +The Webhook provider supports custom annotations for DNS records. This feature allows users to define additional configuration options for DNS records managed by the Webhook provider. Custom annotations are defined using the annotation format `external-dns.alpha.kubernetes.io/webhook-`. + +Custom annotations can be used to influence DNS record creation and updates. Providers implementing the Webhook API should document the custom annotations they support and how they affect DNS record management. + ## Provider registry To simplify the discovery of providers, we will accept pull requests that will add links to providers in the [README](../../README.md) file. This list will only serve the purpose of simplifying finding providers and will not constitute an official endorsement of any of the externally implemented providers unless otherwise stated. diff --git a/provider/webhook/webhook_test.go b/provider/webhook/webhook_test.go index 03b02c20f..999cdc3bf 100644 --- a/provider/webhook/webhook_test.go +++ b/provider/webhook/webhook_test.go @@ -26,6 +26,7 @@ import ( "github.com/stretchr/testify/require" "sigs.k8s.io/external-dns/endpoint" + "sigs.k8s.io/external-dns/plan" "sigs.k8s.io/external-dns/provider" webhookapi "sigs.k8s.io/external-dns/provider/webhook/api" ) @@ -217,3 +218,54 @@ func TestAdjustendpointsWithError(t *testing.T) { require.Error(t, err) require.ErrorIs(t, err, provider.SoftError) } + +// test apply changes with an endpoint with a provider specific property +func TestApplyChangesWithProviderSpecificProperty(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 + } + if r.URL.Path == "/records" { + w.Header().Set(webhookapi.ContentTypeHeader, webhookapi.MediaTypeFormatAndVersion) + // assert that the request contains the provider specific property + var changes plan.Changes + defer r.Body.Close() + b, err := io.ReadAll(r.Body) + require.Nil(t, err) + err = json.Unmarshal(b, &changes) + require.Nil(t, err) + require.Len(t, changes.Create, 1) + require.Len(t, changes.Create[0].ProviderSpecific, 1) + require.Equal(t, "prop1", changes.Create[0].ProviderSpecific[0].Name) + require.Equal(t, "value1", changes.Create[0].ProviderSpecific[0].Value) + w.WriteHeader(http.StatusNoContent) + return + } + })) + defer svr.Close() + + p, err := NewWebhookProvider(svr.URL) + require.NoError(t, err) + e := &endpoint.Endpoint{ + DNSName: "test.example.com", + RecordTTL: 10, + RecordType: "A", + Targets: endpoint.Targets{ + "", + }, + ProviderSpecific: endpoint.ProviderSpecific{ + endpoint.ProviderSpecificProperty{ + Name: "prop1", + Value: "value1", + }, + }, + } + err = p.ApplyChanges(context.TODO(), &plan.Changes{ + Create: []*endpoint.Endpoint{ + e, + }, + }) + require.NoError(t, err) +} diff --git a/source/source.go b/source/source.go index c7d46c970..132f40dcd 100644 --- a/source/source.go +++ b/source/source.go @@ -224,6 +224,13 @@ func getProviderSpecificAnnotations(annotations map[string]string) (endpoint.Pro Name: fmt.Sprintf("ibmcloud-%s", attr), Value: v, }) + } else if strings.HasPrefix(k, "external-dns.alpha.kubernetes.io/webhook-") { + // Support for wildcard annotations for webhook providers + attr := strings.TrimPrefix(k, "external-dns.alpha.kubernetes.io/webhook-") + providerSpecificAnnotations = append(providerSpecificAnnotations, endpoint.ProviderSpecificProperty{ + Name: fmt.Sprintf("webhook/%s", attr), + Value: v, + }) } } return providerSpecificAnnotations, setIdentifier