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

DigitalOcean: support multiple targets per endpoint #1595

Conversation

tdyas
Copy link
Contributor

@tdyas tdyas commented May 22, 2020

This PR teaches the DigialOcean provider how to support multiple targets per endpoint. (The DigitalOcean provider currently only supports one endpoint per target which other providers do support.)

The Problem

I am running nginx-ingress in DaemonSet mode with host networking enabled on my Kubernetes cluster. I want the IPs for every node running nginx-ingress to appear as A records in DNS. First, because the DigitalOcean provider only supports one endpoint per ingress currently, only one of the A records is created which means the additional nginx-ingress pods will not receive traffic.

Moreover, because external-dns believes that there should be multiple A records for the endpoint in question, the reconciliation loop never converges and external-dns continually sends update API calls every minute. This is not how external-dns seems intended to operate. (Indeed, with this PR, the reconciliation loop does converge and avoids sending an update every minute.)

Solution

If the DigitalOcean API were like the AWS or GCP APIs, then the API representation of a DNS record would have an attribute that is a list of RR datas, and supporting multiple targets per endpoint would be as simple as setting that attribute to the list of targets. The DigitalOcean API is not like that though because it represents multiple A records as multiple "domain record" instances.

This representation is actually quite similar to the Linode API. The Linode provider models updates by expanding an endpoint with multiple targets into multiple domain records to be sent to the Linode API. I have taken that approach with this PR: The DigitalOcean provider now expands an endpoint with multiple targets into multiple godo.DomainRecord instances.

Overview of the changes:

  1. The provider's Records method uses the new mergeEndpointsByNameType function to combine multiple godo.DomainRecords for the same DNS name into a single endpoint.Endpoint with multiple targets. This maps the DigitalOcean representation to the external-dns data model

  2. The provider's ApplyChanges method has been rewritten to compute a set of digitalOceanChangeCreate, digitalOceanChangeUpdate, and digitalOceanChangeDelete instances representing how to modify the godo.DomainRecord instances associated with a godo.Domain. Computation of each type of change has been put into the processCreateActions, processUpdateActions, and processDeleteActions functions.

  3. Tests: Lots more testing of individual functions. I added go-cmp to the project so I could use its Equal and Diff functions. These handle structs with nested pointers to other structs much better than the testify package. I did that so I could actually compare the *godo.DomainRecordEditRequest struct contained in the change structs. (Added a TODO to try and see if testify would be willing to allow custom matching functions.)

  4. Upgraded godo to the latest just to keep it current. go bumped the version of two other packages in the go.mod as well, not sure why it did that.

This is currently in production for my cluster. Seems to be working nicely. I did some basic tests against production by deleting and adding some records and external-dns figures out what changed and fixes it. And the reconciliation loop actually converges.

@k8s-ci-robot
Copy link
Contributor

Thanks for your pull request. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

📝 Please follow instructions at https://git.k8s.io/community/CLA.md#the-contributor-license-agreement to sign the CLA.

It may take a couple minutes for the CLA signature to be fully registered; after that, please reply here with a new comment and we'll verify. Thanks.


Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here.

@k8s-ci-robot k8s-ci-robot added the cncf-cla: no Indicates the PR's author has not signed the CNCF CLA. label May 22, 2020
@k8s-ci-robot
Copy link
Contributor

Welcome @tdyas!

It looks like this is your first PR to kubernetes-sigs/external-dns 🎉. Please refer to our pull request process documentation to help your PR have a smooth ride to approval.

You will be prompted by a bot to use commands during the review process. Do not be afraid to follow the prompts! It is okay to experiment. Here is the bot commands documentation.

You can also check if kubernetes-sigs/external-dns has its own contribution guidelines.

You may want to refer to our testing guide if you run into trouble with your tests not passing.

If you are having difficulty getting your pull request seen, please follow the recommended escalation practices. Also, for tips and tricks in the contribution process you may want to read the Kubernetes contributor cheat sheet. We want to make sure your contribution gets all the attention it needs!

Thank you, and welcome to Kubernetes. 😃

@tdyas
Copy link
Contributor Author

tdyas commented May 22, 2020

/assign @hjacobs
(the k8s-ci-robot said to assign)

@k8s-ci-robot k8s-ci-robot added cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. and removed cncf-cla: no Indicates the PR's author has not signed the CNCF CLA. labels May 22, 2020
@k8s-ci-robot k8s-ci-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label May 31, 2020
@tdyas tdyas force-pushed the digitalocean_support_multiple_targets branch from 7a34cd0 to f19d0bc Compare May 31, 2020 18:53
@k8s-ci-robot k8s-ci-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label May 31, 2020
@tdyas
Copy link
Contributor Author

tdyas commented May 31, 2020

/assign @Raffo

@tdyas
Copy link
Contributor Author

tdyas commented Jun 4, 2020

cc @andrewsomething: Just a heads up in case anyone at DigitalOcean has an interest in external-dns or Kubernetes stuff.

@tdyas tdyas force-pushed the digitalocean_support_multiple_targets branch from d0af711 to ba05243 Compare June 9, 2020 14:59
Copy link
Contributor

@Raffo Raffo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for this PR @tdyas especially for the great explanation of what this is doing, I really enjoyed reading it.
I added a few minor comments, but overall the code looks okay.

ttl = int(endpoint.RecordTTL)
// ApplyChanges applies the given set of generic changes to the provider.
func (p *DigitalOceanProvider) ApplyChanges(ctx context.Context, planChanges *plan.Changes) error {
// TODO: This should only retrieve zones affected by the given `planChanges`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have this done before merging this PR or do you want to keep it like this? What are the consequences?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not implementing this TODO would leave the status quo in place which is that we would just retrieve all of the records that Records retrieves, just as the existing version of the provider does. (--domain-filter would still be applied to limit the provider to only those zones where external-dns is managing records.)

My concern here was for avoiding having to retrieve all of the records if the zone had potentially many records. #1429 was on my mind as it flagged too many API calls as a potential hazard in such cases.

This TODO is a nice to have but should not block landing this PR.

provider/digitalocean/digital_ocean_test.go Outdated Show resolved Hide resolved
provider/digitalocean/digital_ocean_test.go Outdated Show resolved Hide resolved
@Raffo
Copy link
Contributor

Raffo commented Jun 14, 2020

@andrewsomething should you be willing to maintain the DO provider, feel free to ping me here or on slack, we are trying to scale how we maintain providers and we would definitely be happy to have someone from DO maintain the DO provider 😄

@k8s-ci-robot k8s-ci-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jun 17, 2020
@tdyas tdyas force-pushed the digitalocean_support_multiple_targets branch from 7174db3 to 84e514b Compare June 19, 2020 06:38
@k8s-ci-robot k8s-ci-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jun 19, 2020
@Raffo
Copy link
Contributor

Raffo commented Jun 24, 2020

/approve
/lgtm

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Jun 24, 2020
@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: Raffo, tdyas

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jun 24, 2020
@k8s-ci-robot k8s-ci-robot merged commit b616801 into kubernetes-sigs:master Jun 24, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. lgtm "Looks good to me", indicates that a PR is ready to be merged. size/XL Denotes a PR that changes 500-999 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants