Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions netdiff/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
from .parsers.bmx6 import Bmx6Parser # noqa
from .parsers.netjson import NetJsonParser # noqa
from .parsers.cnml import CnmlParser # noqa
from .parsers.openvpn import OpenvpnParser #noqa
from .utils import diff # noqa
45 changes: 45 additions & 0 deletions netdiff/parsers/openvpn.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import networkx
from openvpn_status import parse_status

from .base import BaseParser


class OpenvpnParser(BaseParser):
""" OpenVPN status log parser """
protocol = 'OpenVPN Status Log'
version = '1'
metric = 'static'
# for internal use only
_server_common_name = 'openvpn-server'

def to_python(self, data):
return parse_status(data)

def parse(self, data):
"""
Converts a OpenVPN JSON to a NetworkX Graph object
which is then returned.
"""
# initialize graph and list of aggregated nodes
graph = networkx.Graph()
server = self._server_common_name
# add server (central node) to graph
graph.add_node(server)
# add clients in graph as nodes
for common_name, client in data.client_list.items():
client_properties = {
'real_address': str(client.real_address.host),
'port': client.real_address.port,
'connected_since': client.connected_since.strftime('%Y-%m-%dT%H:%M:%SZ'),
'bytes_received': client.bytes_received,
'bytes_sent': client.bytes_sent
}
if common_name in data.routing_table:
client_properties['local_addresses'] = [
str(data.routing_table.get(common_name).virtual_address)
]
graph.add_node(common_name, **client_properties)
# add links in routing table to graph
for common_name, link in data.routing_table.items():
graph.add_edge(server, common_name, weight=1)
return graph
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ networkx<2.0
requests<3.0
six
libcnml<0.10.0
openvpn-status<0.2
12 changes: 12 additions & 0 deletions tests/static/openvpn-2-links.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
OpenVPN CLIENT LIST
Updated,Thu Jun 18 08:12:15 2015
Common Name,Real Address,Bytes Received,Bytes Sent,Connected Since
node1,87.18.10.87:49502,334948,1973012,Thu Jun 18 04:23:03 2015
node2,93.40.230.50:64169,1817262,28981224,Thu Jun 18 04:08:39 2015
ROUTING TABLE
Virtual Address,Common Name,Real Address,Last Ref
192.168.255.134,node1,87.18.10.87:49502,Thu Jun 18 08:12:09 2015
192.168.255.126,node2,93.40.230.50:64169,Thu Jun 18 08:11:55 2015
GLOBAL STATS
Max bcast/mcast queue length,0
END
33 changes: 33 additions & 0 deletions tests/test_openvpn.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import os

import networkx
import six
from netdiff import OpenvpnParser
from netdiff.exceptions import ParserError, TopologyRetrievalError
from netdiff.tests import TestCase

CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
links2 = open('{0}/static/openvpn-2-links.txt'.format(CURRENT_DIR)).read()


class TestOpenvpnParser(TestCase):

def test_parse(self):
p = OpenvpnParser(links2)
self.assertIsInstance(p.graph, networkx.Graph)
self.assertEqual(p.version, '1')
self.assertEqual(p.metric, 'static')

def test_json_dict(self):
p = OpenvpnParser(links2)
data = p.json(dict=True)
self.assertIsInstance(data, dict)
self.assertEqual(data['type'], 'NetworkGraph')
self.assertEqual(data['protocol'], 'OpenVPN Status Log')
self.assertEqual(data['version'], '1')
self.assertEqual(data['revision'], None)
self.assertEqual(data['metric'], 'static')
self.assertIsInstance(data['nodes'], list)
self.assertIsInstance(data['links'], list)
self.assertEqual(len(data['nodes']), 3)
self.assertEqual(len(data['links']), 2)