github.com/StackExchange/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  ```