github.com/teknogeek/dnscontrol@v0.2.8/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 dicuss 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, GANDI). 95 * **incremental-record:** The API lets you add/change/delete individual DNS records. (ACTIVEDIR, CLOUDFLARE, NAMEDOTCOM, GCLOUD, ROUTE53) 96 * **incremental-label:** Similar to incremental, but the API requires you to update all the records related to a particular label each time. For example, if a label (www.example.com) has an A and MX record, any change requires replacing all the records for that label. 97 98 TODO: Categorize DNSIMPLE, NAMECHEAP 99 100 All providers use the "diff" module to detect differences. It takes 101 two zones and returns records that are unchanged, created, deleted, 102 and modified. The incremental providers use the differences to 103 update individual records or recordsets. The zone providers use the 104 information to print a human-readable list of what is being changed, 105 but upload the entire new zone. 106 107 108 ## Step 3: Create the driver skeleton 109 110 Create a directory for the provider called `providers/name` where 111 `name` is all lowercase and represents the commonly-used name for 112 the service. 113 114 The main driver should be called `providers/name/nameProvider.go`. 115 The API abstraction is usually in a separate file (often called 116 `api.go`). 117 118 119 ## Step 4: Activate the driver 120 121 Edit 122 [providers/_all/all.go](https://github.com/StackExchange/dnscontrol/blob/master/providers/_all/all.go). 123 Add the provider list so DNSControl knows it exists. 124 125 ## Step 5: Implement 126 127 Implement all the calls in 128 [providers.DNSServiceProvider interface.](https://godoc.org/github.com/StackExchange/dnscontrol/providers#DNSServiceProvider). 129 130 The function `GetDomainCorrections` is a bit interesting. It returns 131 a list of corrections to be made. These are in the form of functions 132 that DNSControl can call to actually make the corrections. 133 134 ## Step 6: Unit Test 135 136 Make sure the existing unit tests work. Add unit tests for any 137 complex algorithms in the new code. 138 139 Run the unit tests with this command: 140 141 cd dnscontrol 142 go test ./... 143 144 145 ## Step 7: Integration Test 146 147 This is the most important kind of testing when adding a new provider. 148 Integration tests use a test account and a real domain. 149 150 * Edit [integrationTest/providers.json](https://github.com/StackExchange/dnscontrol/blob/master/integrationTest/providers.json): Add the creds.json info required for this provider. 151 152 For example, this will run the tests using BIND: 153 154 ``` 155 cd dnscontrol/integrationTest 156 go test -v -verbose -provider BIND 157 ``` 158 159 (BIND is a good place to start since it doesn't require any API keys.) 160 161 This will run the tests on Amazon AWS Route53: 162 163 ``` 164 export R53_DOMAIN=dnscontroltest-r53.com # Use a test domain. 165 export R53_KEY_ID=CHANGE_TO_THE_ID 166 export R53_KEY='CHANGE_TO_THE_KEY' 167 go test -v -verbose -provider ROUTE53 168 ``` 169 170 ## Step 8: Update docs 171 172 * Edit [README.md](https://github.com/StackExchange/dnscontrol): Add the provider to the bullet list. 173 * Edit [docs/provider-list.md](https://github.com/StackExchange/dnscontrol/blob/master/docs/provider-list.md): Add the provider to the provider list. 174 * Create `docs/_providers/PROVIDERNAME.md`: Use one of the other files in that directory as a base. 175 * Edit [OWNERS](https://github.com/StackExchange/dnscontrol/blob/master/OWNERS): Add the directory name and your github id. 176 177 ## Step 9: Submit a PR 178 179 At this point you can submit a PR. 180 181 Actually you can submit the PR even earlier if you just want feedback, 182 input, or have questions. This is just a good stopping place to 183 submit a PR if you haven't already. 184 185 186 ## Step 10: Capabilities 187 188 Some DNS providers have features that others do not. For example some 189 support the SRV record. A provider announces what it can do using 190 the capabilities system. 191 192 If a provider doesn't advertise a particular capability, the integration 193 test system skips the appropriate tests. Therefore you might want 194 to initially develop the provider with no particular capabilities 195 advertised and code until all the integration tests work. Then 196 enable capabilities one at a time to finish off the project. 197 198 Don't feel obligated to implement everything at once. In fact, we'd 199 prefer a few small PRs than one big one. Focus on getting the basic 200 provider working well before adding these extras. 201 202 Operational features have names like `providers.CanUseSRV` and 203 `providers.CanUseAlias`. The list of optional "capabilities" are 204 in the file `dnscontrol/providers/providers.go` (look for `CanUseAlias`). 205 206 Capabilities are processed early by DNSControl. For example if a 207 provider doesn't support SRV records, DNSControl will error out 208 when parsing dnscontrol.js rather than waiting until the API fails 209 at the very end. 210 211 Enable optional capabilities in the nameProvider.go file and run 212 the integration tests to see what works and what doesn't. Fix any 213 bugs and repeat, repeat, repeat until you have all the capabilities 214 you want to implement. 215 216 FYI: If a provider's capabilities changes, run `go generate` to update 217 the documentation. 218 219 220 ## Vendoring Dependencies 221 222 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 suffient: 223 224 ``` 225 go get github.com/kardianos/govendor 226 govendor add +e 227 ```