Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support multi-value A-records #93

Open
2 tasks done
r35krag0th opened this issue Feb 27, 2025 · 8 comments
Open
2 tasks done

Support multi-value A-records #93

r35krag0th opened this issue Feb 27, 2025 · 8 comments
Labels
bug Something isn't working help wanted Extra attention is needed

Comments

@r35krag0th
Copy link

Feature Description

I'm not sure if this is intentional or not (limitations of UniFi's API), but currently any multi-value A-records will only write the first value to the UniFi DNS API.

The Istio Ingress GW has 3 External IPs.

kubectl get svc/istio-ingressgateway -n istio-system

NAME                   TYPE        CLUSTER-IP    EXTERNAL-IP                           PORT(S)                    AGE
istio-ingressgateway   ClusterIP   10.43.45.47   10.0.43.221,10.0.43.231,10.0.43.241   15021/TCP,80/TCP,443/TCP   140d

But only the first one gets written.

# Checking what was written
dig @10.0.42.1 api.dev.r35.network
10.0.43.221

Search

  • I have searched the open and closed issues for duplicates

Code of Conduct

  • I agree to follow this project's Code of Conduct
@kashalls
Copy link
Owner

This is a known issue, at least for me: https://github.com/kashalls/external-dns-unifi-webhook/blob/main/internal/unifi/client.go#L221

UniFi only supports creating 1:1 records. I need a way to match up 1:* without making it super complicated (as external-dns can have many targets as possible)

When ExternalDNS calls GetRecords, it is going to want to match the state of the cluster itself. I'm open to ideas on how to do this.

@kashalls kashalls added bug Something isn't working help wanted Extra attention is needed labels Feb 27, 2025
@r35krag0th
Copy link
Author

I do know you can have multiple A records with the same name (left hand value) in UniFi DNS.

I need to sit down and learn more about the implementation to really have a good grasp. I'm definitely highly invested in getting this to work.

@kashalls
Copy link
Owner

I need to sit down and learn more about the implementation to really have a good grasp. I'm definitely highly invested in getting this to work.

I made #94 to build a "test". When it's finished building that image, can you test the tag pr-94 and see if by chance that works? Sorry about the experimentation 😺

@kashalls
Copy link
Owner

Here's an image to test: ghcr.io/kashalls/external-dns-unifi-webhook:pr-94

@r35krag0th
Copy link
Author

r35krag0th commented Feb 27, 2025

I can confirm that does in fact create the additional records correctly. Looks like a good fix to me.

I'll create another ticket for better handling reconciliation (using sync policy) where the behavior seems to be:

  1. delete all records that match discovered endpoints
  2. delete all registry records
  3. create all records with current data
  4. create all registry records

@kashalls
Copy link
Owner

I can confirm that does in fact create the additional records correctly. Looks like a good fix to me.

Does external-dns seem to endlessly sync instead of occuring once and just idling?

@r35krag0th
Copy link
Author

r35krag0th commented Feb 27, 2025

I can confirm that does in fact create the additional records correctly. Looks like a good fix to me.

Does external-dns seem to endlessly sync instead of occuring once and just idling?

It does run once and pause for the next interval.

Logs

external-dns-unifi-7f75c99dbf-4plth webhook {"level":"debug","ts":1740668586.6443675,"caller":"unifi/provider.go:67","msg":"deleting endpoint","name":"api.dev.r35.network","type":"A"}
external-dns-unifi-7f75c99dbf-4plth webhook {"level":"debug","ts":1740668586.6740441,"caller":"unifi/client.go:283","msg":"Client deleted record","record":{"_id":"67c07e71d7ba2a44bdc7e5dc","enabled":true,"key":"api.dev.r35.network","port":0,"priority":0,"record_type":"A","value":"10.0.43.221","weight":0}}
external-dns-unifi-7f75c99dbf-4plth webhook {"level":"debug","ts":1740668586.685423,"caller":"unifi/client.go:283","msg":"Client deleted record","record":{"_id":"67c07e71d7ba2a44bdc7e5de","enabled":true,"key":"api.dev.r35.network","port":0,"priority":0,"record_type":"A","value":"10.0.43.231","weight":0}}
external-dns-unifi-7f75c99dbf-4plth webhook {"level":"debug","ts":1740668586.6964533,"caller":"unifi/client.go:283","msg":"Client deleted record","record":{"_id":"67c07e71d7ba2a44bdc7e5e0","enabled":true,"key":"api.dev.r35.network","port":0,"priority":0,"record_type":"A","value":"10.0.43.241","weight":0}}
external-dns-unifi-7f75c99dbf-4plth webhook {"level":"debug","ts":1740668588.3212514,"caller":"unifi/provider.go:67","msg":"deleting endpoint","name":"k8s.api.dev.r35.network","type":"TXT"}
external-dns-unifi-7f75c99dbf-4plth webhook {"level":"debug","ts":1740668588.3508084,"caller":"unifi/client.go:283","msg":"Client deleted record","record":{"_id":"67c07e73d7ba2a44bdc7e670","enabled":true,"key":"k8s.api.dev.r35.network","port":0,"priority":0,"record_type":"TXT","value":"\"heritage=external-dns,external-dns/owner=rke2,external-dns/resource=gateway/istio-system/r35-api-dev-gateway\"","weight":0}}
external-dns-unifi-7f75c99dbf-4plth webhook {"level":"debug","ts":1740668588.3508756,"caller":"unifi/provider.go:67","msg":"deleting endpoint","name":"k8s.a-api.dev.r35.network","type":"TXT"}
external-dns-unifi-7f75c99dbf-4plth webhook {"level":"debug","ts":1740668588.3787184,"caller":"unifi/client.go:283","msg":"Client deleted record","record":{"_id":"67c07e73d7ba2a44bdc7e672","enabled":true,"key":"k8s.a-api.dev.r35.network","port":0,"priority":0,"record_type":"TXT","value":"\"heritage=external-dns,external-dns/owner=rke2,external-dns/resource=gateway/istio-system/r35-api-dev-gateway\"","weight":0}}
external-dns-unifi-7f75c99dbf-4plth webhook {"level":"debug","ts":1740668589.8568807,"caller":"unifi/provider.go:76","msg":"creating endpoint","name":"api.dev.r35.network","type":"A"}
external-dns-unifi-7f75c99dbf-4plth webhook {"level":"debug","ts":1740668589.8725803,"caller":"unifi/client.go:257","msg":"client created new record","record":{"_id":"67c07eadd7ba2a44bdc7e77c","enabled":true,"key":"api.dev.r35.network","port":0,"priority":0,"record_type":"A","value":"10.0.43.221","weight":0}}
external-dns-unifi-7f75c99dbf-4plth webhook {"level":"debug","ts":1740668589.8858943,"caller":"unifi/client.go:257","msg":"client created new record","record":{"_id":"67c07eadd7ba2a44bdc7e77e","enabled":true,"key":"api.dev.r35.network","port":0,"priority":0,"record_type":"A","value":"10.0.43.231","weight":0}}
external-dns-unifi-7f75c99dbf-4plth webhook {"level":"debug","ts":1740668589.9016798,"caller":"unifi/client.go:257","msg":"client created new record","record":{"_id":"67c07eadd7ba2a44bdc7e780","enabled":true,"key":"api.dev.r35.network","port":0,"priority":0,"record_type":"A","value":"10.0.43.241","weight":0}}
external-dns-unifi-7f75c99dbf-4plth webhook {"level":"debug","ts":1740668591.1220295,"caller":"unifi/provider.go:76","msg":"creating endpoint","name":"k8s.api.dev.r35.network","type":"TXT"}
external-dns-unifi-7f75c99dbf-4plth webhook {"level":"debug","ts":1740668591.1358945,"caller":"unifi/client.go:257","msg":"client created new record","record":{"_id":"67c07eafd7ba2a44bdc7e814","enabled":true,"key":"k8s.api.dev.r35.network","port":0,"priority":0,"record_type":"TXT","value":"\"heritage=external-dns,external-dns/owner=rke2,external-dns/resource=gateway/istio-system/r35-api-dev-gateway\"","weight":0}}
external-dns-unifi-7f75c99dbf-4plth webhook {"level":"debug","ts":1740668591.135968,"caller":"unifi/provider.go:76","msg":"creating endpoint","name":"k8s.a-api.dev.r35.network","type":"TXT"}
external-dns-unifi-7f75c99dbf-4plth webhook {"level":"debug","ts":1740668591.1497874,"caller":"unifi/client.go:257","msg":"client created new record","record":{"_id":"67c07eafd7ba2a44bdc7e816","enabled":true,"key":"k8s.a-api.dev.r35.network","port":0,"priority":0,"record_type":"TXT","value":"\"heritage=external-dns,external-dns/owner=rke2,external-dns/resource=gateway/istio-system/r35-api-dev-gateway\"","weight":0}}

Summarized

  1. deletes endpoint api.dev.r35.network
    1. delete 10.0.43.221
    2. delete 10.0.43.231
    3. delete 10.0.43.241
  2. delete endpoints for registry records
    1. delete registry record k8s.api.dev.r35.network
    2. delete registry record k8s.a-api.dev.r35.network2. create endpoint and records (A)
  3. create endpoint api.dev.r35.network
    1. create 10.0.43.221
    2. create 10.0.43.231
    3. create 10.0.43.241
  4. create endpoints for registry records
    1. create registry record k8s.api.dev.r35.network
    2. create registry record k8s.a-api.dev.r35.network

@kashalls
Copy link
Owner

Does external-dns seem to endlessly sync instead of occuring once and just idling?

It does run once and pause for the next interval.

I just checked and this implementation allows for the records to be created and deleted. However, the GetEndpoints is still returning the wrong response to ExternalDNS causing the records to be constantly updated (by being deleted and created every time it sync's) when I create three kubernetes secrets with different external ips and identical hostnames. It would not be a good idea for this to be pushed to main as is IMO.

Not against the idea of supporting this, just no known way to fix this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

2 participants