How to extend Coin

Coin can be extended by writing your own backends, so that you can support various access technologies by using the tools you want.

The common part of Coin already handles the administrative details of subscriptions: members, subscriptions cost and billing strategy, generating bills, etc.

It also handles the IP allocation process. The administrator can define pools of IP addresses, in which subnets are automatically allocated to subscribers. Each subscription can be attached any number of IPv4 or IPv6 subnets, which somehow get routed to the subscriber (the actual way of doing this depends on the backend). Management of reverse DNS is an upcoming feature.

All the rest is up to you, that is, the technical side of subscriptions. You will probably want to handle:

  • authentication (e.g. Radius login and password, TLS certificates...)

  • accounting (e.g. collecting and displaying graphs of user traffic)

  • routing (e.g. inserting static routes, or signalling a routing daemon about new routes)

  • technology-specific information (e.g. phone number associated to a DSL line, MAC address of a CPE, GPS coordinates for wireless subscribers)

  • stuff we didn't think about when writing this

This can be done in three steps:

  • write a Django application, whose models describe the data you need

  • optionally, implement views for presenting some of this information to users

  • write a backend to distribute needed configuration data to the rest of the infrastructure (routers, switches, log servers, accounting backend...)

How you implement the actual backend is completely up to you. It can be a SQL database (useful for Radius), a LDAP database, simply inserting static routes in the kernel (if Coin runs on one of your routers, which is probably not a good idea), writing configuration to text files, relying on an orchestration tool such as Puppet or Ansible, etc.

Simple example: no view, no backend

A very simple application is provided with Coin: it's called simple_dsl.

This application provides a simple model for DSL subscribers (just a phone number, no authentication), and doesn't use any backend. It is intended more as a demonstration, but it is perfectly usable, and should fulfil the needs of small ISPs selling "white label" DSL lines.

It is probably a good starting point for writing your own application. If you need more features, read on.

More complex example with views and a LDAP backend

See coin/vpn for a much more complex application: OpenVPN access with login/password and an arbitrary number of subnets routed to the user. The user has an interface for generating a password and for choosing which IP addresses it wants to use. All this configuration data is pushed to a LDAP database, which is then used by the OpenVPN server. OpenVPN interfaces with LDAP both natively (for authenticating users) and through shell scripts (for routes and IP addresses).

Complete specification


Your model must inherit from coin.configuration.models.Configuration. This way, it will be automatically integrated in the generic admin interface, and will gain the ability to be associated to IP subnets.

If you define a Meta class with a verbose_name attribute, it will be used to identify your configuration backend in the interface (otherwise the name of the class will be used).

If you want to provide views for your model, you must define an url_namespace attribute, which is a string defining the URL namespace associated to your view. By default, the (lowercased) name of the class will be used.

You should also define a subnet_event(self) method, which will be called whenever the IP subnets associated to a configuration object have changed (new subnet, deleted subnet, modified subnet). You can use the ip_subnet related name to have access to all IP subnets associated to the object (for instance, self.ip_subnet.all() will give you a list of coin.resources.models.IPSubnet objects).

Note that, like all Django models, you should define a __unicode__ method to describe an object of your class.


Your admin model must inherit from coin.configuration.admin.ConfigurationAdminFormMixin and polymorphic.admin.PolymorphicChildModelAdmin (in this order). Otherwise, it's a perfectly regular admin model (see simple_dsl), except for the specificities described below.

You must define a inline attribute, set to an inline admin model for your model (for instance, built on admin.StackedInline or admin.TabularInline; again, see simple_dsl). This inline model will be used in the generic admin interface, so that administrators can edit the backend details directly from a subscription object.

If you don't have any view, remember to set the view_on_site attribute to False, so that Django's admin will not show a "View on site" button.


If you want to provide views for your model, you must provide at least a "details" view, which will be used to display information about your configuration objects to end-users. For instance, you can inherit from django.views.generic.detail.DetailView, or django.views.generic.edit.UpdateView if you want users to edit some of the fields (see coin/vpn/views.py).

Here is an example URL pattern to be used in your urls.py:

url(r'^(?P<id>\d+)$', VPNView.as_view(template_name="vpn/vpn.html"), name="details")

Note that this pattern must be called "details". Of course, you can add as many additional views as you want.


App views URLs are pluggable, you only have to tell your app to declare its URLs. Then its URLs will be available under <app_name>/<view_name> (as long s your app is listed in INSTALLED_APPS).

To do so :

  1. Create a <app_name>/apps.py like (important part is inheriting coin.apps.AppURLs) :

    from django.apps import AppConfig import coin.apps

    class MyAppConfig(AppConfig, coin.apps.AppURLs):

    name = 'myapp'
    verbose_name = "Fruity app !"
  2. Edit a <app_dir>/__init__.py :

    default_app_config = 'coin.myapp.apps.MyAppConfig

Optionaly, you can customize which URLs are plugged and to which prefix via the exported_urlpatterns var on your config class as a list of <prefix>,<urlpatterns> :

    class MyAppConfig(AppConfig, coin.apps.AppURLS):
        name = 'my_app'
        exported_urlpatterns = [('coolapp', 'my_app.cool_urls')]

Of course, you can add as many additional views as you want.


app-specific templates and static files should be placed according to the reusable apps layout.

  • E.g. app-specific css : /static//css/local.css
  • E.g. app-specific template : /templates//base.html

    In order to load app-specific CSS and JavaScript, you may want to use the extra_css and extra_js template blocks, defined in main base.html.


    {% extends "base.html" %}
    {% block extra_css %}<link rel="stylesheet" href="{% static "myapp/css/local.css" %}">{% endblock %}
    {% block extra_js %}<script>alert("So extra !");</script>{% endblock %}

    Menu items

    If you want to add your own links to the main coin menu (left sidebar); edit the coin/templates/menu_items.html adding a conditional like that :

    {% if 'my_app' in INSTALLED_APPS %}
    {% endif %}

    … That way, your links will display only if your app is enabled.