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.
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.
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).
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 :
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 !"
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.
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.
Example:
{% 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 %}
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 %}
<li></li>
{% endif %}
… That way, your links will display only if your app is enabled.