Skip to content

Commit 778def3

Browse files
authored
Merge branch 'master' into record-traceback-separately
2 parents 20bcb38 + ec56134 commit 778def3

14 files changed

Lines changed: 160 additions & 26 deletions

File tree

CHANGES.rst

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
11
Change log
22
==========
33

4-
Version 0.6.2 [unreleased]
4+
Version 0.6.3 [unreleased]
55
--------------------------
66

77
WIP
88

9+
Version 0.6.2 [2017-08-29]
10+
--------------------------
11+
12+
- `#78 <https://github.com/openwisp/netjsonconfig/issues/78>`_
13+
[base] Added support for multiple renderers
14+
- `#94 <https://github.com/openwisp/netjsonconfig/issues/94>`_
15+
[schema] Made ``bssid`` not required for wireless stations
16+
- `#97 <https://github.com/openwisp/netjsonconfig/issues/97>`_
17+
[python2] Fixed ``py2-ipaddress`` related unicode bug
18+
919
Version 0.6.1 [2017-07-05]
1020
--------------------------
1121

README.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,14 @@ netjsonconfig
1313

1414
.. image:: https://badge.fury.io/py/netjsonconfig.svg
1515
:target: http://badge.fury.io/py/netjsonconfig
16+
17+
.. image:: https://img.shields.io/gitter/room/nwjs/nw.js.svg?style=flat-square
18+
:target: https://gitter.im/openwisp/general
1619

1720
------------
1821

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

2125
.. image:: http://netjsonconfig.openwisp.org/en/latest/_images/openwisp.org.svg
2226
:target: http://openwisp.org

bin/netjsonconfig

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
#!/usr/bin/env python
22

3+
import argparse
34
import os
45
import sys
6+
57
import six
6-
import argparse
8+
79
import netjsonconfig
810
import traceback
911

@@ -57,7 +59,7 @@ output = parser.add_argument_group('output')
5759

5860
output.add_argument('--backend', '-b',
5961
required=True,
60-
choices=['openwrt', 'openwisp', 'openvpn'],
62+
choices=netjsonconfig.get_backends().keys(),
6163
action='store',
6264
type=str,
6365
help='Configuration backend')
@@ -167,13 +169,8 @@ context = dict(os.environ)
167169
method = args.method
168170
method_arguments = parse_method_arguments(args.args)
169171

170-
backends = {
171-
'openwrt': netjsonconfig.OpenWrt,
172-
'openwisp': netjsonconfig.OpenWisp,
173-
'openvpn': netjsonconfig.OpenVpn
174-
}
175172

176-
backend_class = backends[args.backend]
173+
backend_class = netjsonconfig.get_backends()[args.backend]
177174
try:
178175
options = dict(templates=templates, context=context)
179176
if args.config:
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
2+
===================
3+
Create your backend
4+
===================
5+
6+
.. include:: ../_github.rst
7+
8+
Every backend is based on the common ground of some elements provided by the
9+
netjsonconfig library. The `BaseBackend`, `BaseConverter`, `BaseParser` and
10+
`BaseRenderer` are a battle proven set of tools that can be extended when
11+
creating you backend.
12+
13+
But the netjsonconfig package is not a playground to experiment, your contributions
14+
to a new backend should start elsewhere, a different package, where you are in control
15+
and can make errors and experiment more.
16+
17+
Netjsonconfig can now discover packages that provides a custom backend using
18+
a feature available in the Python packaging ecosystem which is called `entry_points`.
19+
20+
To create a new backend start from scratch with a new folder and add this file to your
21+
project root directory.
22+
23+
.. code-block:: python
24+
25+
# setup.py
26+
from setuptools import setup, find_packages
27+
28+
setup(
29+
name='example_backend',
30+
version='0.0.0',
31+
description='an example to illustrate a netjsonconfig backend as an external module',
32+
packages=find_packages(),
33+
entry_points={
34+
'netjsonconfig.backends': [
35+
'example=example_backend.__init__:ExampleBackend',
36+
]
37+
}
38+
)
39+
40+
this file can be used to create a package that can be installed using pip or other tools
41+
in the python ecosystem. You can find more information about Python packaging
42+
`at packaging.python.org <https://packaging.python.org/>`_
43+
and `at the hitchhikers guide to packaging <https://the-hitchhikers-guide-to-packaging.readthedocs.io/en/latest/>`_.
44+
45+
The most important part is to give your package a good name, a well thought description and
46+
to add the `entry_points` keyword argument with the following code
47+
48+
.. code-block:: python
49+
50+
{
51+
# this is used by netjsonconfig
52+
# to find your backend
53+
'netjsonconfig.backends': [
54+
...
55+
]
56+
}
57+
58+
Now your package will be in the list of backends that netjsonconfig can use!
59+
60+
But we still have to give us a name to be unique! Netjsonconfig already
61+
defined the names `openwisp`, `openwrt` and `openvpn` but you can choose
62+
whatever you like most.
63+
64+
The name `netjsonconfig.backends` will be associated with a list of classes
65+
from your package that will be presented to netjconfig at runtime. To specify
66+
which classes you want to expose write the triple `name`, `path` and `class_name`
67+
using the format `name=path:class_name` as in the example below.
68+
69+
The `path` part is simply the path to the file that contains the class
70+
you want to expose and the `class_name` is the name of the class.
71+
72+
.. code-block:: python
73+
74+
{
75+
'netjsonconfig.backends': [
76+
# name=path:class_name
77+
'example=example_backend.__init__:ExampleBackend',
78+
]
79+
}
80+
81+
The previous example can be used with the following class definition
82+
83+
.. code-block:: python
84+
85+
# example_backend/__init__.py
86+
from netjsonconfig.backends.base.backend import BaseBackend
87+
from netjsonconfig.backends.base.renderer import BaseRenderer
88+
from netjsonconfig.backends.base.parser import BaseParser
89+
90+
from netjsonconfig.schema import schema as default_schema
91+
92+
class ExampleBackend(BaseBackend):
93+
schema = default_schema
94+
converter = []
95+
parser = BaseParser
96+
renderer = BaseRenderer

docs/source/index.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ netjsonconfig
1515
.. image:: https://badge.fury.io/py/netjsonconfig.svg
1616
:target: http://badge.fury.io/py/netjsonconfig
1717

18-
Netjsonconfig is part of the `OpenWISP project <http://openwisp.org>`_.
18+
.. image:: https://img.shields.io/gitter/room/nwjs/nw.js.svg?style=flat-square
19+
:target: https://gitter.im/openwisp/general
20+
21+
Netjsonconfig is part of the `OpenWISP project <http://openwrt.org>`_ and it's the official
22+
configuration engine of `OpenWISP 2 <https://github.com/openwisp/ansible-openwisp2>`_.
1923

2024
.. image:: ./images/openwisp.org.svg
2125
:target: http://openwisp.org
@@ -51,6 +55,7 @@ Contents:
5155
/backends/openwrt
5256
/backends/openwisp
5357
/backends/openvpn
58+
/backends/create_your_backend
5459
/general/commandline_utility
5560
/general/running_tests
5661
/general/contributing

netjsonconfig/__init__.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,24 @@
1+
from pkg_resources import iter_entry_points
2+
import logging
3+
14
from .version import VERSION, __version__, get_version # noqa
25

36
from .backends.openwrt.openwrt import OpenWrt # noqa
47
from .backends.openwisp.openwisp import OpenWisp # noqa
58
from .backends.openvpn.openvpn import OpenVpn # noqa
9+
10+
11+
def get_backends():
12+
default = {
13+
'openwrt': OpenWrt,
14+
'openwisp': OpenWisp,
15+
'openvpn': OpenVpn,
16+
}
17+
logger = logging.getLogger(__name__)
18+
19+
for entry_point in iter_entry_points('netjsonconfig.backends'):
20+
try:
21+
default.update({entry_point.name.lower(): entry_point.load()})
22+
except ImportError as e: # noqa
23+
logger.error("Error loading backend {}".format(entry_point.name.lower()))
24+
return default

netjsonconfig/backends/openwrt/converters/interfaces.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def __intermediate_addresses(self, interface):
6868
# do not use CIDR notation when using a single ipv4
6969
# see https://github.com/openwisp/netjsonconfig/issues/54
7070
if len(static.get('ipaddr', [])) == 1:
71-
network = ip_interface(static['ipaddr'][0])
71+
network = ip_interface(six.text_type(static['ipaddr'][0]))
7272
static['ipaddr'] = str(network.ip)
7373
static['netmask'] = str(network.netmask)
7474
# do not use lists when using a single ipv6 address
@@ -269,7 +269,7 @@ def __netjson_addresses(self, interface):
269269
return interface
270270

271271
def __netjson_address(self, address, interface):
272-
ip = ip_interface(address)
272+
ip = ip_interface(six.text_type(address))
273273
family = 'ipv{0}'.format(ip.version)
274274
netjson = OrderedDict((
275275
('address', str(ip.ip)),
@@ -279,7 +279,7 @@ def __netjson_address(self, address, interface):
279279
))
280280
uci_gateway_key = 'gateway' if family == 'ipv4' else 'ip6gw'
281281
gateway = interface.get(uci_gateway_key, None)
282-
if gateway and ip_address(gateway) in ip.network:
282+
if gateway and ip_address(six.text_type(gateway)) in ip.network:
283283
netjson['gateway'] = gateway
284284
del interface[uci_gateway_key]
285285
return netjson

netjsonconfig/backends/openwrt/converters/routes.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from ipaddress import ip_interface
22

3+
import six
4+
35
from ..schema import schema
46
from .base import OpenWrtConverter
57

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

1820
def __intermediate_route(self, route, index):
19-
network = ip_interface(route.pop('destination'))
21+
network = ip_interface(six.text_type(route.pop('destination')))
2022
target = network.ip if network.version == 4 else network.network
2123
route.update({
2224
'.type': 'route{0}'.format('6' if network.version == 6 else ''),
@@ -50,7 +52,7 @@ def __netjson_route(self, route, i):
5052
network = '{0}/{1}'.format(network, route.pop('netmask'))
5153
route.update({
5254
"device": route.pop('interface'),
53-
"destination": str(ip_interface(network)),
55+
"destination": str(ip_interface(six.text_type(network))),
5456
"next": route.pop('gateway'),
5557
"cost": route.pop('metric', self._schema['properties']['cost']['default'])
5658
})

netjsonconfig/backends/openwrt/converters/rules.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from ipaddress import ip_network
22

3+
import six
4+
35
from ..schema import schema
46
from .base import OpenWrtConverter
57

@@ -21,9 +23,9 @@ def __intermediate_rule(self, rule, index):
2123
dest_net = None
2224
family = 4
2325
if 'src' in rule:
24-
src_net = ip_network(rule['src'])
26+
src_net = ip_network(six.text_type(rule['src']))
2527
if 'dest' in rule:
26-
dest_net = ip_network(rule['dest'])
28+
dest_net = ip_network(six.text_type(rule['dest']))
2729
if dest_net or src_net:
2830
family = dest_net.version if dest_net else src_net.version
2931
rule.update({

netjsonconfig/backends/openwrt/schema.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
from ..openvpn.schema import base_openvpn_schema
77
from .timezones import timezones
88

9-
109
default_radio_driver = "mac80211"
1110

1211

0 commit comments

Comments
 (0)