Commit graph

24 commits

Author SHA1 Message Date
tridion
f1b30a1a04
feat: Add IGNORE_EXTERNAL_DNS() for Kubernetes external-dns coexistence (#3869)s
## Summary

This PR adds a new domain modifier `IGNORE_EXTERNAL_DNS()` that
automatically detects and ignores DNS records managed by Kubernetes
[external-dns](https://github.com/kubernetes-sigs/external-dns)
controller.

**Related Issue:** This addresses the feature request discussed in
StackExchange/dnscontrol#935 (Idea: Ownership system), where
@tlimoncelli indicated openness to accepting a PR for this
functionality.

## Problem

When running DNSControl alongside Kubernetes external-dns, users face a
challenge:

- **external-dns** dynamically creates DNS records based on Kubernetes
Ingress/Service resources
- Users cannot use `IGNORE()` because they cannot predict which record
names external-dns will create
- Using `NO_PURGE()` is too broad - it prevents DNSControl from cleaning
up any orphaned records

The fundamental issue is that `IGNORE()` requires static patterns known
at config-time, but external-dns creates records dynamically at runtime.

## Solution

`IGNORE_EXTERNAL_DNS()` solves this by detecting external-dns managed
records at runtime:

```javascript
D("example.com", REG_CHANGEME, DnsProvider(DSP_MY_PROVIDER),
    IGNORE_EXTERNAL_DNS(),  // Automatically ignore external-dns managed records
    A("@", "1.2.3.4"),
    CNAME("www", "@")
);
```

### How It Works

external-dns uses a TXT record registry to track ownership. For each
managed record, it creates a TXT record like:

- `a-myapp.example.com` → TXT containing
`heritage=external-dns,external-dns/owner=...`
- `cname-api.example.com` → TXT containing
`heritage=external-dns,external-dns/owner=...`

This PR:
1. Scans existing TXT records for the `heritage=external-dns` marker
2. Parses the TXT record name prefix (e.g., `a-`, `cname-`) to determine
the managed record type
3. Automatically adds those records to the ignore list during diff
operations

## Changes

| File | Purpose |
|------|---------|
| `models/domain.go` | Add `IgnoreExternalDNS` field to DomainConfig |
| `pkg/js/helpers.js` | Add `IGNORE_EXTERNAL_DNS()` JavaScript helper |
| `pkg/diff2/externaldns.go` | Core detection logic for external-dns TXT
records |
| `pkg/diff2/externaldns_test.go` | Unit tests for detection logic |
| `pkg/diff2/handsoff.go` | Integrate external-dns detection into
handsoff() |
| `pkg/diff2/diff2.go` | Pass IgnoreExternalDNS flag to handsoff() |
| `commands/types/dnscontrol.d.ts` | TypeScript definitions for IDE
support |
| `documentation/.../IGNORE_EXTERNAL_DNS.md` | User documentation |

## Design Philosophy

This follows DNSControl's pattern of convenience builders (like
`M365_BUILDER`, `SPF_BUILDER`, `DKIM_BUILDER`) that make complex
operations simple. Just as those builders abstract away implementation
details, `IGNORE_EXTERNAL_DNS()` abstracts away the complexity of
detecting external-dns managed records.

## Testing

All unit tests pass:
```
go test ./pkg/diff2/... -v  # Tests detection logic
go test ./pkg/js/...        # Tests JS helpers
go build ./...              # Builds successfully
```

## Caveats Documented

- Only supports TXT registry (the default for external-dns)
- Requires external-dns to use default naming conventions
- May need updates if external-dns changes its registry format

---------

Co-authored-by: Tom Limoncelli <6293917+tlimoncelli@users.noreply.github.com>
2025-12-03 08:56:55 -05:00
James O'Gorman
4ce19352e9
PORKBUN: Improve retry handling, mark as concurrent (#3652) 2025-07-09 12:03:59 -04:00
Tom Limoncelli
a341022068
BUGFIX: IGNORE() deletes ignored records on ByZone() platforms (#3263) 2024-12-18 20:34:52 -05:00
Tom Limoncelli
06ba3cce77
Bugfix: Providers with batched updates might not report the correct number of changes (#3108) 2024-09-16 12:20:30 -04:00
Tom Limoncelli
798c0d6b9e deadcode: Change/ChangeList.String 2024-03-03 15:42:49 -05:00
Tom Limoncelli
790513a170
CHORE: Fix golint and staticcheck errors/warnings (#2717) 2023-12-11 16:24:11 -05:00
Vincent Hagen
e32bdc053f
NEW FEATURE: Order changes based on the record dependencies (#2419)
Co-authored-by: Tom Limoncelli <tlimoncelli@stackoverflow.com>
Co-authored-by: Tom Limoncelli <tal@whatexit.org>
2023-08-29 14:00:09 -04:00
tomf
a7fe17a29c
Display changes, even if upstream has no records. (#2531)
Co-authored-by: Tom Limoncelli <tlimoncelli@stackoverflow.com>
2023-08-24 10:29:27 -04:00
Tom Limoncelli
0b7dabacc8
NEW FEATURE: IGNORE() (diff2 only) (#2388)
Co-authored-by: Jeffrey Cafferata <jeffrey@jcid.nl>
2023-05-24 15:14:36 -04:00
nemunaire
5ae231030e
Update version in go.mod (#2382) 2023-05-20 13:21:45 -04:00
Tom Limoncelli
780e17ada9
Linting (#2308)
Co-authored-by: Tom Limoncelli <tal@whatexit.org>
2023-05-01 18:40:10 -04:00
Tom Limoncelli
be8495c5e8
Integration tests should test diff2's IGNORE* (#2292)
Co-authored-by: Tom Limoncelli <tal@whatexit.org>
2023-04-23 13:28:18 -05:00
Tom Limoncelli
2a28d81490
MSDNS: be more efficient with ttl changes (#2251)
Co-authored-by: Tom Limoncelli <tal@whatexit.org>
2023-03-31 09:08:26 -04:00
Tom Limoncelli
f676c4956e
diff2: Add a "hints" when change is TTL-only (#2249)
Co-authored-by: Tom Limoncelli <tal@whatexit.org>
2023-03-29 14:34:10 -04:00
Vincent Hagen
9ffec690f5
TRANSIP: Improve diff2 implementation (#2228)
Co-authored-by: Tom Limoncelli <tlimoncelli@stackoverflow.com>
2023-03-26 12:51:45 -04:00
Tom Limoncelli
81054e72c5
CHORE: linting (#2176) 2023-03-15 18:35:34 -04:00
Tom Limoncelli
2586e2b611
CORE: Clean up diff2 code in prep for production (#2104) 2023-02-28 01:25:09 -05:00
Tom Limoncelli
05dc26bf2e
BUG: diff2: ttl changes don't always work (#2093) 2023-02-25 22:40:54 -05:00
Jeffrey Cafferata
ab872cc13f
CHORE: Go fmt (#2095)
Co-authored-by: Tom Limoncelli <tlimoncelli@stackoverflow.com>
2023-02-25 22:20:12 -05:00
Tom Limoncelli
fc3a217dc1
Bugfixed: NO_PURGE now works on all diff2 providers (#2084) 2023-02-19 12:33:08 -05:00
Tom Limoncelli
de202531cb
NEW FEATURE: NO_PURGE reports what is not purged (diff2 only) (#2031) 2023-02-01 07:27:00 -05:00
Tom Limoncelli
214eaeb84d
DOCS: Clarify ByRecord() assertions (#1931) 2023-01-11 12:17:34 -05:00
Tom Limoncelli
397ce107e5
REFACTOR: Add a backwards compatible interface to diff2 (#1870) 2022-12-30 21:53:50 -05:00
Tom Limoncelli
54fc2e9ce3
NEW FEATURE: diff2: A better "diff" mechanism (#1852) 2022-12-11 17:28:58 -05:00