github.com/teknogeek/dnscontrol/v2@v2.10.1-0.20200227202244-ae299b55ba42/docs/writing-providers.md (about) 1 --- 2 layout: default 3 title: Writing new DNS providers 4 --- 5 6 # Writing new DNS providers 7 8 Writing a new DNS provider is a relatively straightforward process. 9 You essentially need to implement the 10 [providers.DNSServiceProvider interface.](https://godoc.org/github.com/StackExchange/dnscontrol/providers#DNSServiceProvider) 11 and the system takes care of the rest. 12 13 Please do note that if you submit a new provider you will be 14 assigned bugs related to the provider in the future (unless 15 you designate someone else as the maintainer). More details 16 [here](provider-list.md). 17 18 ## Overview 19 20 I'll ignore all the small stuff and get to the point. 21 22 A provider's `GetDomainCorrections()` function is the workhorse 23 of the provider. It is what gets called by `dnscontrol preview` 24 and `dnscontrol push`. 25 26 How does a provider's `GetDomainCorrections()` function work? 27 28 The goal of `GetDomainCorrections()` is to return a list of 29 corrections. Each correction is a text string describing the change 30 ("Delete CNAME record foo") and a function that, if called, will 31 make the change (i.e. call the API and delete record foo). Preview 32 mode simply prints the text strings. `dnscontrol push` prints the 33 strings and calls the functions. Because of how Go's functions work, 34 the function will have everything it needs to make the change. 35 Pretty cool, eh? 36 37 So how does `GetDomainCorrections()` work? 38 39 First, some terminology: The DNS records specified in the dnsconfig.js 40 file are called the "desired" records. The DNS records stored at 41 the DNS service provider are called the "existing" records. 42 43 Every provider does the same basic process. The function 44 `GetDomainCorrections()` is called with a list of the desired DNS 45 records (`dc.Records`). It then contacts the provider's API and 46 gathers the existing records. It converts the existing records into 47 a list of `*models.RecordConfig`. 48 49 Now that it has the desired and existing records in the appropriate 50 format, `differ.IncrementalDiff(existingRecords)` is called and 51 does all the hard work of understanding the DNS records and figuring 52 out what changes need to be made. It generates lists of adds, 53 deletes, and changes. 54 55 `GetDomainCorrections()` then generates the list of `models.Corrections()` 56 and returns. DNSControl takes care of the rest. 57 58 So, what does all this mean? 59 60 It basically means that writing a provider is as simple as writing 61 code that (1) downloads the existing records, (2) converts each 62 records into `models.RecordConfig`, (3) write functions that perform 63 adds, changes, and deletions. 64 65 If you are new to Go, there are plenty of providers you can copy 66 from. In fact, many non-Go programmers 67 [have learned Go by contributing to DNSControl](https://everythingsysadmin.com/2017/08/go-get-up-to-speed.html). 68 69 Oh, and what if the API simply requires that the entire zonefile be uploaded 70 every time? We still generate the text descriptions of the changes (so that 71 `dnscontrol preview` looks nice) but the functions are just no-ops, except 72 for one that uploads the new zonefile. 73 74 Now that you understand the general process, here are the details. 75 76 ## Step 1: General advice 77 78 A provider can be a DnsProvider, a Registrar, or both. We recommend 79 you write the DnsProvider first, release it, and then write the 80 Registrar if needed. 81 82 If you have any questions, please discuss them in the Github issue 83 related to the request for this provider. Please let us know what 84 was confusing so we can update this document with advice for future 85 authors (or even better, update [this document](https://github.com/StackExchange/dnscontrol/blob/master/docs/writing-providers.md) 86 yourself.) 87 88 89 ## Step 2: Pick a base provider 90 91 Pick a similar provider as your base. Providers basically fall 92 into three general categories: 93 94 * **zone:** The API requires you to upload the entire zone every time. (BIND). 95 * **incremental-record:** The API lets you add/change/delete individual DNS records. (ACTIVEDIR, CLOUDFLARE, DNSIMPLE, NAMEDOTCOM, GCLOUD, ROUTE53) 96 * **incremental-label:** Like incremental-record, but if there are 97 multiple records on a label (for example, example www.example.com 98 has A and MX records), you have to replace all the records at that 99 label. (GANDI_V5) 100 * **incremental-label-type:** Like incremental-record, but updates to any records at a label have to be done by type. For example, if a label (www.example.com) has many A and MX records, even the smallest change to one of the A records requires replacing all the A records. Any changes to the MX records requires replacing all the MX records. If an A record is converted to a CNAME, one must remove all the A records in one call, and add the CNAME record with another call. This is deceptively difficult to get right; if you have the voice between incremental-label-type and incremental-label, pick incremental-label. 101 102 TODO: Categorize NAMECHEAP 103 104 All providers use the "diff" module to detect differences. It takes 105 two zones and returns records that are unchanged, created, deleted, 106 and modified. 107 The zone providers use the 108 information to print a human-readable list of what is being changed, 109 but upload the entire new zone. 110 The incremental providers use the differences to 111 update individual records or recordsets. 112 113 114 ## Step 3: Create the driver skeleton 115 116 Create a directory for the provider called `providers/name` where 117 `name` is all lowercase and represents the commonly-used name for 118 the service. 119 120 The main driver should be called `providers/name/nameProvider.go`. 121 The API abstraction is usually in a separate file (often called 122 `api.go`). 123 124 125 ## Step 4: Activate the driver 126 127 Edit 128 [providers/_all/all.go](https://github.com/StackExchange/dnscontrol/blob/master/providers/_all/all.go). 129 Add the provider list so DNSControl knows it exists. 130 131 ## Step 5: Implement 132 133 Implement all the calls in 134 [providers.DNSServiceProvider interface.](https://godoc.org/github.com/StackExchange/dnscontrol/providers#DNSServiceProvider). 135 136 The function `GetDomainCorrections` is a bit interesting. It returns 137 a list of corrections to be made. These are in the form of functions 138 that DNSControl can call to actually make the corrections. 139 140 ## Step 6: Unit Test 141 142 Make sure the existing unit tests work. Add unit tests for any 143 complex algorithms in the new code. 144 145 Run the unit tests with this command: 146 147 cd dnscontrol 148 go test ./... 149 150 151 ## Step 7: Integration Test 152 153 This is the most important kind of testing when adding a new provider. 154 Integration tests use a test account and a real domain. 155 156 * Edit [integrationTest/providers.json](https://github.com/StackExchange/dnscontrol/blob/master/integrationTest/providers.json): Add the creds.json info required for this provider. 157 158 For example, this will run the tests using BIND: 159 160 ``` 161 cd dnscontrol/integrationTest 162 go test -v -verbose -provider BIND 163 ``` 164 165 (BIND is a good place to start since it doesn't require any API keys.) 166 167 This will run the tests on Amazon AWS Route53: 168 169 ``` 170 export R53_DOMAIN=dnscontroltest-r53.com # Use a test domain. 171 export R53_KEY_ID='CHANGE_TO_THE_ID' 172 export R53_KEY='CHANGE_TO_THE_KEY' 173 go test -v -verbose -provider ROUTE53 174 ``` 175 176 ## Step 8: Update docs 177 178 * Edit [README.md](https://github.com/StackExchange/dnscontrol): Add the provider to the bullet list. 179 * Edit [docs/provider-list.md](https://github.com/StackExchange/dnscontrol/blob/master/docs/provider-list.md): Add the provider to the provider list. 180 * FYI: The list of "Requested Providers" is generated dynamically from Github issues tagged `provider-request`. When you close the issue related to your provider, the list will update automatically. 181 * Create `docs/_providers/PROVIDERNAME.md`: Use one of the other files in that directory as a base. 182 * Edit [OWNERS](https://github.com/StackExchange/dnscontrol/blob/master/OWNERS): Add the directory name and your github id. 183 184 ## Step 9: Submit a PR 185 186 At this point you can submit a PR. 187 188 Actually you can submit the PR even earlier if you just want feedback, 189 input, or have questions. This is just a good stopping place to 190 submit a PR if you haven't already. 191 192 193 ## Step 10: Capabilities 194 195 Some DNS providers have features that others do not. For example some 196 support the SRV record. A provider announces what it can do using 197 the capabilities system. 198 199 If a provider doesn't advertise a particular capability, the integration 200 test system skips the appropriate tests. Therefore you might want 201 to initially develop the provider with no particular capabilities 202 advertised and code until all the integration tests work. Then 203 enable capabilities one at a time to finish off the project. 204 205 Don't feel obligated to implement everything at once. In fact, we'd 206 prefer a few small PRs than one big one. Focus on getting the basic 207 provider working well before adding these extras. 208 209 Operational features have names like `providers.CanUseSRV` and 210 `providers.CanUseAlias`. The list of optional "capabilities" are 211 in the file `dnscontrol/providers/providers.go` (look for `CanUseAlias`). 212 213 Capabilities are processed early by DNSControl. For example if a 214 provider doesn't support SRV records, DNSControl will error out 215 when parsing dnscontrol.js rather than waiting until the API fails 216 at the very end. 217 218 Enable optional capabilities in the nameProvider.go file and run 219 the integration tests to see what works and what doesn't. Fix any 220 bugs and repeat, repeat, repeat until you have all the capabilities 221 you want to implement. 222 223 FYI: If a provider's capabilities changes, run `go generate` to update 224 the documentation. 225 226 227 ## Vendoring Dependencies 228 229 If your provider depends on other go packages, then you must vendor them. To do this, use [govendor](https://github.com/kardianos/govendor). A command like this is usually sufficient: 230 231 ``` 232 go get github.com/kardianos/govendor 233 govendor add +e 234 ```