sk2 / autonetkit

AutoNetkit: an automated network configuration engine
BSD 3-Clause "New" or "Revised" License
129 stars 49 forks source link

Allow JSON import format #222

Closed sk2 closed 3 years ago

sk2 commented 10 years ago

Provide a reader similar to read_graphml to import JSON. proposed mapping is:

{'directed': False,
 'graph': [],
 'links': [{'dst': ('eth0', 'r2'), 'src': ('eth0', 'r1')},
           {'dst': ('eth2', 'r2'), 'src': ('eth0', 'r4')},
           {'dst': ('eth0', 'r3'), 'src': ('eth1', 'r1')},
           {'dst': ('eth1', 'r3'), 'src': ('eth1', 'r2')},
           {'dst': ('eth0', 'r5'), 'src': ('eth1', 'r4')},
           {'dst': ('eth2', 'r3'), 'src': ('eth1', 'r5')}],
 'multigraph': False,
 'nodes': [{'asn': 1,
            'device_type': 'router',
            'id': 'r1',
            'label': 'r1',
            'ports': [{'category': 'physical',
                       'description': None,
                       'id': 'Loopback0'},
                      {'category': 'physical',
                       'description': 'r1 to r2',
                       'id': 'eth0'},
                      {'category': 'physical',
                       'description': 'r1 to r3',
                       'id': 'eth1'}],
            'x': 350,
            'y': 400},
           {'asn': 1,
            'device_type': 'router',
            'id': 'r2',
            'label': 'r2',
            'ports': [{'category': 'loopback',
                       'description': None,
                       'id': 'Loopback0'},
                      {'category': 'physical',
                       'description': 'r2 to r1',
                       'id': 'eth0'},
                      {'category': 'physical',
                       'description': 'r2 to r3',
                       'id': 'eth1'},
                      {'category': 'physical',
                       'description': 'r2 to r4',
                       'id': 'eth2'}],
            'x': 500,
            'y': 300},
           {'asn': 1,
            'device_type': 'router',
            'id': 'r3',
            'label': 'r3',
            'ports': [{'category': 'loopback',
                       'description': None,
                       'id': 'Loopback0'},
                      {'category': 'physical',
                       'description': 'r3 to r1',
                       'id': 'eth0'},
                      {'category': 'physical',
                       'description': 'r3 to r2',
                       'id': 'eth1'},
                      {'category': 'physical',
                       'description': 'r3 to r5',
                       'id': 'eth2'}],
            'x': 500,
            'y': 500},
           {'asn': 2,
            'device_type': 'router',
            'id': 'r4',
            'label': 'r4',
            'ports': [{'category': 'loopback',
                       'description': None,
                       'id': 'Loopback0'},
                      {'category': 'physical',
                       'description': 'r4 to r2',
                       'id': 'eth0'},
                      {'category': 'physical',
                       'description': 'r4 to r5',
                       'id': 'eth1'}],
            'x': 675,
            'y': 300},
           {'asn': 2,
            'device_type': 'router',
            'id': 'r5',
            'label': 'r5',
            'ports': [{'category': 'loopback',
                       'description': None,
                       'id': 'Loopback0'},
                      {'category': 'physical',
                       'description': 'r5 to r4',
                       'id': 'eth0'},
                      {'category': 'physical',
                       'description': 'r5 to r3',
                       'id': 'eth1'}],
            'x': 675,
            'y': 500}]}
Lennie commented 10 years ago

Not sure how you handled it in the rest of the project, but in the first part (links) you list the interface first and device second. Wouldn't it be more readable the other way around ?

Lennie commented 10 years ago

Ohh, and it wasn't valid JSON.

Something like this would be better:

{"directed": false,
 "graph": [],
 "links": [{"dst": ["eth0", "r2"], "src": ["eth0", "r1"]},
           {"dst": ["eth2", "r2"], "src": ["eth0", "r4"]},
           {"dst": ["eth0", "r3"], "src": ["eth1", "r1"]},
           {"dst": ["eth1", "r3"], "src": ["eth1", "r2"]},
           {"dst": ["eth0", "r5"], "src": ["eth1", "r4"]},
           {"dst": ["eth2", "r3"], "src": ["eth1", "r5"]}],
 "multigraph": false,
 "nodes": [{"asn": 1,
            "device_type": "router",
            "id": "r1",
            "label": "r1",
            "ports": [{"category": "physical",
                       "description": null,
                       "id": "Loopback0"},
                      {"category": "physical",
                       "description": "r1 to r2",
                       "id": "eth0"},
                      {"category": "physical",
                       "description": "r1 to r3",
                       "id": "eth1"}],
            "x": 350,
            "y": 400},
           {"asn": 1,
            "device_type": "router",
            "id": "r2",
            "label": "r2",
            "ports": [{"category": "loopback",
                       "description": null,
                       "id": "Loopback0"},
                      {"category": "physical",
                       "description": "r2 to r1",
                       "id": "eth0"},
                      {"category": "physical",
                       "description": "r2 to r3",
                       "id": "eth1"},
                      {"category": "physical",
                       "description": "r2 to r4",
                       "id": "eth2"}],
            "x": 500,
            "y": 300},
           {"asn": 1,
            "device_type": "router",
            "id": "r3",
            "label": "r3",
            "ports": [{"category": "loopback",
                       "description": null,
                       "id": "Loopback0"},
                      {"category": "physical",
                       "description": "r3 to r1",
                       "id": "eth0"},
                      {"category": "physical",
                       "description": "r3 to r2",
                       "id": "eth1"},
                      {"category": "physical",
                       "description": "r3 to r5",
                       "id": "eth2"}],
            "x": 500,
            "y": 500},
           {"asn": 2,
            "device_type": "router",
            "id": "r4",
            "label": "r4",
            "ports": [{"category": "loopback",
                       "description": null,
                       "id": "Loopback0"},
                      {"category": "physical",
                       "description": "r4 to r2",
                       "id": "eth0"},
                      {"category": "physical",
                       "description": "r4 to r5",
                       "id": "eth1"}],
            "x": 675,
            "y": 300},
           {"asn": 2,
            "device_type": "router",
            "id": "r5",
            "label": "r5",
            "ports": [{"category": "loopback",
                       "description": null,
                       "id": "Loopback0"},
                      {"category": "physical",
                       "description": "r5 to r4",
                       "id": "eth0"},
                      {"category": "physical",
                       "description": "r5 to r3",
                       "id": "eth1"}],
            "x": 675,
            "y": 500}]}
sk2 commented 10 years ago

Hi, thanks for the feedback. The illegal JSON would have been from me pasting the Python output before I did the json.dumps() command - oops!

With respect to the ordering, I'm 50/50 on the right approach. In DNS, it's normally eth0.router but I agree that the other way can make sense too. Another approach is

{'src': 'r1', 'src_port': 'eth1',
'dst': 'r2', 'dst_port': 'eth3'}

It's more explicit, but more verbose. Any opinions on either?

I'm pretty open on the format - I'll map it to the internal JSON format used by NetworkX to import it, and it's easy to add new importers. For this format, something that's quick and intuitive is the aim - and if we can remove the requirement for yEd that's ideal.

We can add more complex importers later.

Lennie commented 10 years ago

I thought it looked very Pythonish to me. :-)

I'm a big fan of DNS, for it makes possible, but I don't see any reason to make it DNS-like syntax. Because the only place where I use DNS-like syntax, is well DNS. :-)

On the use of src and src_port, at the end of the day, it doesn't matter all that much, it is only data-interchange format. So maybe because of that, it should be explicit, thus extensible. So you can add something like a VLAN-tag later (if that makes sense).

sk2 commented 10 years ago

I went for

    {
      "dst": "r3", 
      "dst_port": "eth1", 
      "src": "r2", 
      "src_port": "eth1"
    }, 

as it was the cleareest.

Each of the node/interface/port are extensible, and any attribute set will show up directly in the API. I'll add a tutorial when I get the time, that shows this. It's quite powerful to run ANK in live monitor mode, change a single attribute in the JSON and watch the visualization update with the design rules.