Skip to content

Commit

Permalink
Merge branch 'master' into record-traceback-separately
Browse files Browse the repository at this point in the history
  • Loading branch information
nemesifier authored Jul 4, 2018
2 parents 20bcb38 + ec56134 commit 778def3
Show file tree
Hide file tree
Showing 14 changed files with 160 additions and 26 deletions.
12 changes: 11 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
Change log
==========

Version 0.6.2 [unreleased]
Version 0.6.3 [unreleased]
--------------------------

WIP

Version 0.6.2 [2017-08-29]
--------------------------

- `#78 <https://github.com/openwisp/netjsonconfig/issues/78>`_
[base] Added support for multiple renderers
- `#94 <https://github.com/openwisp/netjsonconfig/issues/94>`_
[schema] Made ``bssid`` not required for wireless stations
- `#97 <https://github.com/openwisp/netjsonconfig/issues/97>`_
[python2] Fixed ``py2-ipaddress`` related unicode bug

Version 0.6.1 [2017-07-05]
--------------------------

Expand Down
6 changes: 5 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@ netjsonconfig

.. image:: https://badge.fury.io/py/netjsonconfig.svg
:target: http://badge.fury.io/py/netjsonconfig

.. image:: https://img.shields.io/gitter/room/nwjs/nw.js.svg?style=flat-square
:target: https://gitter.im/openwisp/general

------------

Netjsonconfig is part of the `OpenWISP project <http://openwrt.org>`_.
Netjsonconfig is part of the `OpenWISP project <http://openwisp.org>`_ and it's the official
configuration engine of `OpenWISP 2 <https://github.com/openwisp/ansible-openwisp2>`_.

.. image:: http://netjsonconfig.openwisp.org/en/latest/_images/openwisp.org.svg
:target: http://openwisp.org
Expand Down
13 changes: 5 additions & 8 deletions bin/netjsonconfig
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#!/usr/bin/env python

import argparse
import os
import sys

import six
import argparse

import netjsonconfig
import traceback

Expand Down Expand Up @@ -57,7 +59,7 @@ output = parser.add_argument_group('output')

output.add_argument('--backend', '-b',
required=True,
choices=['openwrt', 'openwisp', 'openvpn'],
choices=netjsonconfig.get_backends().keys(),
action='store',
type=str,
help='Configuration backend')
Expand Down Expand Up @@ -167,13 +169,8 @@ context = dict(os.environ)
method = args.method
method_arguments = parse_method_arguments(args.args)

backends = {
'openwrt': netjsonconfig.OpenWrt,
'openwisp': netjsonconfig.OpenWisp,
'openvpn': netjsonconfig.OpenVpn
}

backend_class = backends[args.backend]
backend_class = netjsonconfig.get_backends()[args.backend]
try:
options = dict(templates=templates, context=context)
if args.config:
Expand Down
96 changes: 96 additions & 0 deletions docs/source/backends/create_your_backend.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@

===================
Create your backend
===================

.. include:: ../_github.rst

Every backend is based on the common ground of some elements provided by the
netjsonconfig library. The `BaseBackend`, `BaseConverter`, `BaseParser` and
`BaseRenderer` are a battle proven set of tools that can be extended when
creating you backend.

But the netjsonconfig package is not a playground to experiment, your contributions
to a new backend should start elsewhere, a different package, where you are in control
and can make errors and experiment more.

Netjsonconfig can now discover packages that provides a custom backend using
a feature available in the Python packaging ecosystem which is called `entry_points`.

To create a new backend start from scratch with a new folder and add this file to your
project root directory.

.. code-block:: python
# setup.py
from setuptools import setup, find_packages
setup(
name='example_backend',
version='0.0.0',
description='an example to illustrate a netjsonconfig backend as an external module',
packages=find_packages(),
entry_points={
'netjsonconfig.backends': [
'example=example_backend.__init__:ExampleBackend',
]
}
)
this file can be used to create a package that can be installed using pip or other tools
in the python ecosystem. You can find more information about Python packaging
`at packaging.python.org <https://packaging.python.org/>`_
and `at the hitchhikers guide to packaging <https://the-hitchhikers-guide-to-packaging.readthedocs.io/en/latest/>`_.

The most important part is to give your package a good name, a well thought description and
to add the `entry_points` keyword argument with the following code

.. code-block:: python
{
# this is used by netjsonconfig
# to find your backend
'netjsonconfig.backends': [
...
]
}
Now your package will be in the list of backends that netjsonconfig can use!

But we still have to give us a name to be unique! Netjsonconfig already
defined the names `openwisp`, `openwrt` and `openvpn` but you can choose
whatever you like most.

The name `netjsonconfig.backends` will be associated with a list of classes
from your package that will be presented to netjconfig at runtime. To specify
which classes you want to expose write the triple `name`, `path` and `class_name`
using the format `name=path:class_name` as in the example below.

The `path` part is simply the path to the file that contains the class
you want to expose and the `class_name` is the name of the class.

.. code-block:: python
{
'netjsonconfig.backends': [
# name=path:class_name
'example=example_backend.__init__:ExampleBackend',
]
}
The previous example can be used with the following class definition

.. code-block:: python
# example_backend/__init__.py
from netjsonconfig.backends.base.backend import BaseBackend
from netjsonconfig.backends.base.renderer import BaseRenderer
from netjsonconfig.backends.base.parser import BaseParser
from netjsonconfig.schema import schema as default_schema
class ExampleBackend(BaseBackend):
schema = default_schema
converter = []
parser = BaseParser
renderer = BaseRenderer
7 changes: 6 additions & 1 deletion docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ netjsonconfig
.. image:: https://badge.fury.io/py/netjsonconfig.svg
:target: http://badge.fury.io/py/netjsonconfig

Netjsonconfig is part of the `OpenWISP project <http://openwisp.org>`_.
.. image:: https://img.shields.io/gitter/room/nwjs/nw.js.svg?style=flat-square
:target: https://gitter.im/openwisp/general

Netjsonconfig is part of the `OpenWISP project <http://openwrt.org>`_ and it's the official
configuration engine of `OpenWISP 2 <https://github.com/openwisp/ansible-openwisp2>`_.

.. image:: ./images/openwisp.org.svg
:target: http://openwisp.org
Expand Down Expand Up @@ -51,6 +55,7 @@ Contents:
/backends/openwrt
/backends/openwisp
/backends/openvpn
/backends/create_your_backend
/general/commandline_utility
/general/running_tests
/general/contributing
Expand Down
19 changes: 19 additions & 0 deletions netjsonconfig/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
from pkg_resources import iter_entry_points
import logging

from .version import VERSION, __version__, get_version # noqa

from .backends.openwrt.openwrt import OpenWrt # noqa
from .backends.openwisp.openwisp import OpenWisp # noqa
from .backends.openvpn.openvpn import OpenVpn # noqa


def get_backends():
default = {
'openwrt': OpenWrt,
'openwisp': OpenWisp,
'openvpn': OpenVpn,
}
logger = logging.getLogger(__name__)

for entry_point in iter_entry_points('netjsonconfig.backends'):
try:
default.update({entry_point.name.lower(): entry_point.load()})
except ImportError as e: # noqa
logger.error("Error loading backend {}".format(entry_point.name.lower()))
return default
6 changes: 3 additions & 3 deletions netjsonconfig/backends/openwrt/converters/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def __intermediate_addresses(self, interface):
# do not use CIDR notation when using a single ipv4
# see https://github.com/openwisp/netjsonconfig/issues/54
if len(static.get('ipaddr', [])) == 1:
network = ip_interface(static['ipaddr'][0])
network = ip_interface(six.text_type(static['ipaddr'][0]))
static['ipaddr'] = str(network.ip)
static['netmask'] = str(network.netmask)
# do not use lists when using a single ipv6 address
Expand Down Expand Up @@ -269,7 +269,7 @@ def __netjson_addresses(self, interface):
return interface

def __netjson_address(self, address, interface):
ip = ip_interface(address)
ip = ip_interface(six.text_type(address))
family = 'ipv{0}'.format(ip.version)
netjson = OrderedDict((
('address', str(ip.ip)),
Expand All @@ -279,7 +279,7 @@ def __netjson_address(self, address, interface):
))
uci_gateway_key = 'gateway' if family == 'ipv4' else 'ip6gw'
gateway = interface.get(uci_gateway_key, None)
if gateway and ip_address(gateway) in ip.network:
if gateway and ip_address(six.text_type(gateway)) in ip.network:
netjson['gateway'] = gateway
del interface[uci_gateway_key]
return netjson
Expand Down
6 changes: 4 additions & 2 deletions netjsonconfig/backends/openwrt/converters/routes.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from ipaddress import ip_interface

import six

from ..schema import schema
from .base import OpenWrtConverter

Expand All @@ -16,7 +18,7 @@ def to_intermediate_loop(self, block, result, index=None):
return result

def __intermediate_route(self, route, index):
network = ip_interface(route.pop('destination'))
network = ip_interface(six.text_type(route.pop('destination')))
target = network.ip if network.version == 4 else network.network
route.update({
'.type': 'route{0}'.format('6' if network.version == 6 else ''),
Expand Down Expand Up @@ -50,7 +52,7 @@ def __netjson_route(self, route, i):
network = '{0}/{1}'.format(network, route.pop('netmask'))
route.update({
"device": route.pop('interface'),
"destination": str(ip_interface(network)),
"destination": str(ip_interface(six.text_type(network))),
"next": route.pop('gateway'),
"cost": route.pop('metric', self._schema['properties']['cost']['default'])
})
Expand Down
6 changes: 4 additions & 2 deletions netjsonconfig/backends/openwrt/converters/rules.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from ipaddress import ip_network

import six

from ..schema import schema
from .base import OpenWrtConverter

Expand All @@ -21,9 +23,9 @@ def __intermediate_rule(self, rule, index):
dest_net = None
family = 4
if 'src' in rule:
src_net = ip_network(rule['src'])
src_net = ip_network(six.text_type(rule['src']))
if 'dest' in rule:
dest_net = ip_network(rule['dest'])
dest_net = ip_network(six.text_type(rule['dest']))
if dest_net or src_net:
family = dest_net.version if dest_net else src_net.version
rule.update({
Expand Down
1 change: 0 additions & 1 deletion netjsonconfig/backends/openwrt/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from ..openvpn.schema import base_openvpn_schema
from .timezones import timezones


default_radio_driver = "mac80211"


Expand Down
2 changes: 1 addition & 1 deletion netjsonconfig/version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
VERSION = (0, 6, 2, 'alpha')
VERSION = (0, 6, 3, 'alpha')
__version__ = VERSION


Expand Down
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
jinja2
jsonschema
jinja2>=2.9,<3.0
jsonschema>=2.6,<2.7
six
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
extras_require = {
# used for wheel package,
# see http://wheel.readthedocs.io/en/latest/#defining-conditional-dependencies
':python_version in "2.6 2.7"' : ['py2-ipaddress']
':python_version in "2.6 2.7"': ['py2-ipaddress']
}


Expand Down
6 changes: 3 additions & 3 deletions tests/openwisp/test_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,9 +211,9 @@ def test_tc_script(self):
self.assertIn('tc class add dev tap0 parent 1 classid 1:1 htb rate 1024kbit burst 191k', contents)
self.assertIn('tc class add dev tap0 parent 1:1 classid 1:2 htb rate 512kbit ceil 1024kbit', contents)
self.assertIn('tc qdisc add dev tap0 ingress', contents)
l = 'tc filter add dev tap0 parent ffff: preference 0 u32 match u32 0x0 0x0 police '\
'rate 2048kbit burst 383k drop flowid :1'
self.assertIn(l, contents)
line = 'tc filter add dev tap0 parent ffff: preference 0 u32 match u32 0x0 0x0 police '\
'rate 2048kbit burst 383k drop flowid :1'
self.assertIn(line, contents)
tar.close()

def test_cron(self):
Expand Down

0 comments on commit 778def3

Please sign in to comment.