Commit graph

54 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
Tom Limoncelli
db21e30abb
Update deps (#3790) 2025-10-10 14:16:46 -04:00
James O'Gorman
4ce19352e9
PORKBUN: Improve retry handling, mark as concurrent (#3652) 2025-07-09 12:03:59 -04:00
Max Chernoff
3ea7ea84c9
FEATURE: Support ignoring the ech= parameter in HTTPS/SVCB RR types (#3485) 2025-06-11 11:16:15 -04:00
Tom Limoncelli
5dbe5e84c9
CHORE: Fix lint warnings from golangci-lint (#3311) 2025-01-13 11:33:12 -05: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
2944eded30
TESTING: Fix reversed got/want output in compareconfig_test.go (#3070) 2024-08-05 16:12:20 -04:00
Tom Limoncelli
798c0d6b9e deadcode: Change/ChangeList.String 2024-03-03 15:42:49 -05:00
Tom Limoncelli
80ff814988 deadcode: groupbyRSet 2024-03-03 15:42:49 -05:00
Tom Limoncelli
34d6e079b2 deadcode: groupbyRSet 2024-03-03 15:42:49 -05:00
Tom Limoncelli
ed999b99bd deadcode: justMsgString (move to test) 2024-03-03 15:42:49 -05:00
Tom Limoncelli
0b8bb1d1ba
FEATURE: Add experimental --reportmax flag (#2719) 2023-12-13 12:32:39 -05:00
Tom Limoncelli
790513a170
CHORE: Fix golint and staticcheck errors/warnings (#2717) 2023-12-11 16:24:11 -05:00
Tom Limoncelli
cbccbbeb8d
REFACTOR: Opinion: TXT records are one long string (#2631)
Co-authored-by: Costas Drogos <costas.drogos@gmail.com>
Co-authored-by: imlonghao <git@imlonghao.com>
Co-authored-by: Jeffrey Cafferata <jeffrey@jcid.nl>
Co-authored-by: Vincent Hagen <blackshadev@users.noreply.github.com>
2023-12-04 17:45:25 -05:00
Tom Limoncelli
3dab594757
CHORE: More cleanups (#2632) 2023-11-19 13:44:49 -05:00
Tom Limoncelli
c91fe6c1c8
CHORE: Remove diff1 from codebase (#2575) 2023-10-22 13:56:13 -04:00
Tom Limoncelli
69bf714852
TESTING: handoff() tests should disable NO_PURGE (#2568) 2023-09-26 11:25:57 -04: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
7fc80ac7cc
CLOUDFLARE: BUGFIX: Proxy=full not handled in diff2 (#2525)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-21 12:19:16 -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
66a76c44c1
Don't count diff2.REPORT (informational warnings) as a "correction" (#2361)
Co-authored-by: Tom Limoncelli <tal@whatexit.org>
2023-05-16 10:42:08 -04:00
Tom Limoncelli
0d479b2780
verifyCNAMEAssertions should warn, not panic (#2340)
Co-authored-by: Tom Limoncelli <tal@whatexit.org>
2023-05-09 14:29:09 -04:00
Tom Limoncelli
ace2242daf
BUG: diff2 doesn't process IGNORE_TARGET() correctly (#2338)
Co-authored-by: Tom Limoncelli <tal@whatexit.org>
2023-05-08 22:29:58 -04:00
Daniil Lemenkov
36e3595612
CHORE: Satisfy Staticcheck and remove unused code (#2331) 2023-05-08 16:49:26 -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
8f4a08a7e6
ROUTE53: Fix "No such DNS type error" on legacy or ignored records (#2294)
Co-authored-by: Tom Limoncelli <tal@whatexit.org>
2023-05-01 18:33:29 -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
Tom Limoncelli
6ac1961341
TESTING: Disable colorized output during tests (#2248)
Co-authored-by: Tom Limoncelli <tal@whatexit.org>
2023-03-29 13:57:49 -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
edf4c92815
FEATURE: Truncate report of ignored/purged items unless --full (#2203)
Co-authored-by: Tom Limoncelli <tal@whatexit.org>
2023-03-20 09:40:28 -04:00
Tom Limoncelli
30646a15f7
CHORE: go generate (#2180) 2023-03-16 09:21:35 -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
e129e40313
FEATURE: Colorize diff2 output (#2103) 2023-02-28 01:14:06 -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
e3dc604247
AZURE_DNS: Convert to use diff2 natively (#2058) 2023-02-07 16:53:49 -05:00
Tom Limoncelli
e1ce6ff34f
CLOUDFLARE: Adopt diff2 (#2040) 2023-02-01 16:18:01 -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
0051b41720
BUGFIX: CREATE may product empty log messages (ByRecordSet) (#2013) 2023-01-29 13:01:40 -05:00
Tom Limoncelli
8249a4b95b
Linting (#1996) 2023-01-28 11:09:38 -05:00
Tom Limoncelli
214eaeb84d
DOCS: Clarify ByRecord() assertions (#1931) 2023-01-11 12:17:34 -05:00
Tom Limoncelli
5c0801f4a8
DOCS: Improve pkg/diff2 documentation (#1903) 2023-01-01 14:14:18 -05:00
Tom Limoncelli
96e4e88fc5
Cleanups (#1871) 2022-12-30 22:03:36 -05:00