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  ```