Fetching contributors…
Cannot retrieve contributors at this time
72 lines (41 sloc) 3.21 KB



Providers are service wrappers that expose a common interface to interacting with them. The DNS Charm spec has a simple and straightforward purpose: to add, remove, or update a pointer/informational record against a given domain. We can achieve communication with any provider through this simple exposed set of methods and consume new services as they emerge.

Requirements for upstream inclusion:

All providers must meet the following criteria for addition:

  • fully unit tested
  • documented in docs/providers/
  • peer-reviewed and acknowledged for merging
  • Self-contained, and relies only on itself for method inclusion
  • Implement the methods outlined in

Adding A Provider:

The charm has a contrib directory that houses all provider code. These are ideally in Python and will consume as few resources as possible to communicate with the provider to ease installation in 'offline' or 'limited connectivity' environments.

Resources that come from locations such as PyPi should be noted in the provider's documentation to ensure anyone deploying to a limited connectivity environment can allocate all required source packages for 'offline installation'. The charm will be forked locally and deployed with files placed in the 'files/provider' directory. All installation logic is then to be handled by the given provider's installation routine.


In the given examples, we will assume there is a DNS provider named GoCheap with a WebAPI, and a wrapping python library named GoCheapLib

Create the Directory Structure

mkdir contrib/gocheap
touch contrib/gocheap/
touch contrib/gocheap/
touch contrib/gocheap/requirements.txt    
touch contrib/tests/

Setup Dependencies

Add any PIP requirements required for installation into provider/requirements.txt.

In our case, requirements.txt will look like the following:


Add Provider Code

In, you need to create a scaffolded provider. In terms of example, you may reference the contrib/bind/ provider code.

Your Provider class should always be Provider(object), as the directory structure will delineate the different providers. Allowing the charm hook wrappers to use inflection to infer the proper class methods to call.

An example skeleton file:

class Provider(object):

    def ConfigChanged(self):
    def AddRecord(self):
    def RemoveRecord(self):
    def UpdateRecord(self):

From this skeleton, you are free to add whatever models, classes, libraries, modules, and other requirements are necessary to integrate with your given provider. In terms of setup with API keys and ensuring they are kept together, there is a configuration variable: provider_keys that should hold the credentials in key|value form. e.g. If your two API tokens are APIKey and APISecret, they would look similar to the following:

APIKey|1234567 APISecret|foobar

i.e. Entries are space-separated, and keys & values are separated from each other with a pipe character.