Skip to content

Commit 108e6c6

Browse files
committed
[feature] Backward conversion #70
- Parsers - command line utility - updated docs - some long test file have been split - openwrt converters have been split Closes #70
1 parent b09c4ed commit 108e6c6

44 files changed

Lines changed: 5755 additions & 2494 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

bin/netjsonconfig

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ parser = argparse.ArgumentParser(description=description,
3434
config = parser.add_argument_group('input')
3535

3636
config.add_argument('--config', '-c',
37-
required=True,
3837
action='store',
3938
type=str,
39+
default=None,
4040
help='config file or string, must be valid NetJSON DeviceConfiguration')
4141

4242
config.add_argument('--templates', '-t',
@@ -46,25 +46,32 @@ config.add_argument('--templates', '-t',
4646
default=[],
4747
help='list of template config files or strings separated by space')
4848

49+
config.add_argument('--native', '-n',
50+
action='store',
51+
type=str,
52+
default=None,
53+
help='path to native configuration file or archive')
54+
4955
output = parser.add_argument_group('output')
5056

5157
output.add_argument('--backend', '-b',
5258
required=True,
53-
choices=['openwrt', 'openwisp'],
59+
choices=['openwrt', 'openwisp', 'openvpn'],
5460
action='store',
5561
type=str,
56-
help='Configuration backend: openwrt or openwisp')
62+
help='Configuration backend')
5763

5864
output.add_argument('--method', '-m',
5965
required=True,
60-
choices=['render', 'generate', 'write', 'validate'],
66+
choices=['render', 'generate', 'write', 'validate', 'json'],
6167
action='store',
6268
help='Backend method to use. '
6369
'"render" returns the configuration in text format; '
6470
'"generate" returns a tar.gz archive as output; '
6571
'"write" is like generate but writes to disk; '
6672
'"validate" validates the combination of config '
67-
'and templates passed in input; ')
73+
'and templates passed in input; '
74+
'"json" returns NetJSON output; ')
6875

6976
output.add_argument('--args', '-a',
7077
nargs='*', # zero or more
@@ -85,14 +92,15 @@ debug.add_argument('--version', '-v',
8592
version=netjsonconfig.get_version())
8693

8794

88-
def _load(config):
95+
def _load(config, read=True):
8996
"""
9097
if config argument does not look like a JSON string
9198
try to read the contents of a file
9299
"""
93100
if not config.strip().startswith('{'):
94101
try:
95-
return open(config, 'r').read()
102+
f = open(config, 'r')
103+
return f.read() if read else f
96104
except IOError:
97105
print('netjsonconfig: cannot open "{0}": '
98106
'file not found'.format(config))
@@ -146,20 +154,32 @@ def print_output(output):
146154

147155

148156
args = parser.parse_args()
149-
config = _load(args.config)
157+
if args.config:
158+
config = _load(args.config)
159+
elif args.native:
160+
native = _load(args.native, read=False)
161+
else:
162+
print('Expected one of the following parameters: "config" or "native"; none found')
163+
sys.exit(1)
150164
templates = [_load(template) for template in args.templates]
151165
context = dict(os.environ)
152166
method = args.method
153167
method_arguments = parse_method_arguments(args.args)
154168

155169
backends = {
156170
'openwrt': netjsonconfig.OpenWrt,
157-
'openwisp': netjsonconfig.OpenWisp
171+
'openwisp': netjsonconfig.OpenWisp,
172+
'openvpn': netjsonconfig.OpenVpn
158173
}
159174

160175
backend_class = backends[args.backend]
161176
try:
162-
instance = backend_class(config, templates=templates, context=context)
177+
options = dict(templates=templates, context=context)
178+
if args.config:
179+
options['config'] = config
180+
else:
181+
options['native'] = native
182+
instance = backend_class(**options)
163183
except TypeError as e:
164184
print('netjsonconfig: invalid JSON passed in config or templates')
165185
sys.exit(2)

docs/source/backends/openwrt.rst

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,15 @@ Initialization
1818

1919
.. automethod:: netjsonconfig.OpenWrt.__init__
2020

21-
Initialization example:
21+
If you are unsure about the meaning of the initalization parameters,
22+
read about the following basic concepts:
23+
24+
* :ref:`configuration_dictionary`
25+
* :ref:`backend`
26+
* :ref:`template`
27+
* :ref:`context`
28+
29+
Initialization example (forward conversion):
2230

2331
.. code-block:: python
2432
@@ -30,12 +38,13 @@ Initialization example:
3038
}
3139
})
3240
33-
If you are unsure about the meaning of the initalization parameters,
34-
read about the following basic concepts:
41+
Initialization example (backward conversion):
3542

36-
* :ref:`configuration_dictionary`
37-
* :ref:`template`
38-
* :ref:`context`
43+
.. code-block:: python
44+
45+
from netjsonconfig import OpenWrt
46+
47+
router = OpenWrt(native=open('./openwrt-config.tar.gz'))
3948
4049
Render method
4150
-------------
@@ -176,6 +185,24 @@ Example:
176185
177186
Will write the configuration archive in ``/tmp/dhcp-router.tar.gz``.
178187

188+
Parse method
189+
------------
190+
191+
.. automethod:: netjsonconfig.OpenWrt.parse
192+
193+
This method is automatically called when initializing the backend
194+
with the ``native`` argument:
195+
196+
.. code-block:: python
197+
198+
from netjsonconfig import OpenWrt
199+
200+
router = OpenWrt(native=open('./openwrt-config.tar.gz'))
201+
202+
The argument passed to ``native`` can be a string containing a dump obtained via
203+
``uci export``, or a file object (real file or ``BytesIO`` instance) representing
204+
a configuration archive in tar.gz format typically used in OpenWRT/LEDE.
205+
179206
JSON method
180207
-----------
181208

docs/source/general/basics.rst

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,11 @@ Basic concepts
44

55
.. include:: ../_github.rst
66

7-
87
Before starting, let's quickly introduce the main concepts used in netjsonconfig:
98

109
* :ref:`configuration_dictionary`: python dictionary representing the configuration of a router
11-
* :ref:`backend`: python class used to process the configuration and generate the final
12-
router configuration
10+
* :ref:`backend`: python class used to convert the *configuration dictionary* to the format used
11+
natively by a router firmware and vice versa
1312
* :ref:`schema`: each backend has a `JSON-Schema <http://json-schema.org>`_ which
1413
defines the useful configuration options that the backend is able to process
1514
* :ref:`validation`: the configuration is validated against its JSON-Schema before
@@ -22,16 +21,16 @@ Before starting, let's quickly introduce the main concepts used in netjsonconfig
2221

2322
.. _configuration_dictionary:
2423

25-
Configuration dictionary
26-
------------------------
24+
NetJSON configuration dictionary
25+
--------------------------------
2726

2827
*netjsonconfig* is an implementation of the `NetJSON <http://netjson.org>`_ format,
2928
more specifically the ``DeviceConfiguration`` object, therefore to understand the
3029
configuration format that the library uses to generate the final router configurations
3130
it is essential to read at least the relevant `DeviceConfiguration section in the
3231
NetJSON RFC <http://netjson.org/rfc.html#rfc.section.5>`_.
3332

34-
Here it is a simple NetJSON DeviceConfiguration object:
33+
Here it is a simple *NetJSON DeviceConfiguration* object represented with a python dictionary:
3534

3635
.. code-block:: python
3736
@@ -94,14 +93,16 @@ From now on we will use the term *configuration dictionary* to refer to
9493
Backend
9594
-------
9695

97-
A backend is a python class used to process the *configuration dictionary* and
98-
generate the final router configuration, each supported firmware or opearting system
99-
will have its own backend and third parties can write their own custom backends.
96+
A backend is a python class used to convert the *configuration dictionary* to the format used
97+
natively by the router (forward conversion, from NetJSON to native) and vice versa (backward conversion,
98+
from native to NetJSON), each supported firmware or opearting system will have its own backend
99+
and third parties can write their own custom backends.
100100

101101
The current implemented backends are:
102102

103103
* :doc:`OpenWrt </backends/openwrt>`
104104
* :doc:`OpenWisp </backends/openwisp>` (based on the ``OpenWrt`` backend)
105+
* :doc:`OpenVpn </backends/openvpn>` (custom backend implementing only OpenVPN configuration)
105106

106107
Example initialization of ``OpenWrt`` backend:
107108

@@ -126,6 +127,21 @@ Example initialization of ``OpenWrt`` backend:
126127
]
127128
})
128129
130+
Each backend will implement **parsers**, **renderers** and **converters** to accomplish its
131+
configuration generation or parsing goals.
132+
133+
The process is best explained with the following diagram:
134+
135+
.. image:: ../images/netjsonconfig-backward-conversion.svg
136+
137+
**Converters** take care of converting between *NetJSON* and the intermediate data structure
138+
(and vice versa).
139+
140+
**Renderers** take care of rendering the intermediate data structure to the native format.
141+
142+
**Parsers** perform the opposite operation of ``Renderers``: they take care of parsing native format and
143+
build the intermediate data structure.
144+
129145
.. _schema:
130146

131147
Schema

docs/source/general/commandline_utility.rst

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ languages.
1111
Check out the available options yourself with::
1212

1313
$ netjsonconfig --help
14-
usage: netjsonconfig [-h] --config CONFIG
15-
[--templates [TEMPLATES [TEMPLATES ...]]] --backend
16-
{openwrt,openwisp} --method {render,generate,write,validate}
17-
[--args [ARGS [ARGS ...]]] [--verbose] [--version]
14+
usage: netjsonconfig [-h] [--config CONFIG]
15+
[--templates [TEMPLATES [TEMPLATES ...]]]
16+
[--native NATIVE] --backend {openwrt,openwisp,openvpn}
17+
--method {render,generate,write,validate,json}
18+
[--args [ARGS [ARGS ...]]] [--verbose] [--version]
1819

1920
Converts a NetJSON DeviceConfiguration object to native router configurations.
2021
Exhaustive documentation is available at: http://netjsonconfig.openwisp.org/
@@ -29,30 +30,34 @@ Check out the available options yourself with::
2930
--templates [TEMPLATES [TEMPLATES ...]], -t [TEMPLATES [TEMPLATES ...]]
3031
list of template config files or strings separated by
3132
space
33+
--native NATIVE, -n NATIVE
34+
path to native configuration file or archive
3235

3336
output:
34-
--backend {openwrt,openwisp}, -b {openwrt,openwisp}
35-
Configuration backend: openwrt or openwisp
36-
--method {render,generate,write}, -m {render,generate,write, validate}
37+
--backend {openwrt,openwisp,openvpn}, -b {openwrt,openwisp,openvpn}
38+
Configuration backend
39+
--method {render,generate,write,validate,json}, -m {render,generate,write,validate,json}
3740
Backend method to use. "render" returns the
3841
configuration in text format; "generate" returns a
3942
tar.gz archive as output; "write" is like generate but
4043
writes to disk; "validate" validates the combination
4144
of config and templates passed in input;
42-
45+
"json" returns NetJSON output:
4346
--args [ARGS [ARGS ...]], -a [ARGS [ARGS ...]]
4447
Optional arguments that can be passed to methods
4548

4649
debug:
4750
--verbose verbose output
4851
--version, -v show program's version number and exit
4952

50-
5153
Here's the common use cases explained::
5254

5355
# generate tar.gz from a NetJSON DeviceConfiguration object and save its output to a file
5456
netjsonconfig --config config.json --backend openwrt --method generate > config.tar.gz
5557

58+
# convert an OpenWRT tar.gz to NetJSON and print to standard output (with 4 space indentation)
59+
netjsonconfig --native config.tar.gz --backend openwrt --method json -a indent=" "
60+
5661
# use write configuration archive to disk in /tmp/routerA.tar.gz
5762
netjsonconfig --config config.json --backend openwrt --method write --args name=routerA path=/tmp/
5863

docs/source/images/netjsonconfig-backward-conversion.svg

Lines changed: 379 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)