Skip to content

Commit

Permalink
Merge pull request #5 from dmfigol/dev
Browse files Browse the repository at this point in the history
Improve README and argparse handling
  • Loading branch information
dmfigol authored Jan 8, 2018
2 parents aeff87b + 273d85e commit 33b654c
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 31 deletions.
37 changes: 33 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,35 @@
# eve-to-gns3-converter
This is a converter which converts topologies created in the networking simulator EVE-NG to GNS3 format
# EVE-NG to GNS3 topology converter
This script converts network topologies created in [EVE-NG](http://www.eve-ng.net) to [GNS3](https://www.gns3.com) format.

Uses **Python 3.6**
Coding of this project was live streamed on [https://twitch.tv/dmfigol](https://twitch.tv/dmfigol)
Recordings are posted on my [YouTube channel](https://www.youtube.com/channel/UCS8yWZCX-fdxft8yFAffZCg)

Coding of this project is livestreamed on https://twitch.tv/dmfigol
To run the script, you will need to have Python 3.6+ installed.
Dependencies are listed in **requirements.txt**. You can install them using:
`pip3 install -r requirements.txt`

### How to use the script
```
python3 eve-to-gns3-converter.py [-h] (-f SRC_TOPOLOGY_FILE | -s SRC_DIR)
[-d DST_DIR] [-c CONSOLE_START_PORT]
[--l2_iol_image L2_IOL_IMAGE]
[--l3_iol_image L3_IOL_IMAGE]
```
Example:
`python3 eve-to-gns3-converter.py -s src/ -d dst/`

#### Arguments:
* **-f, --src_topology_file** specifies a single **.unl* file you would like to convert
Alternatively, use:
* **-s, --src_dir** specifies a source directory containing **.unl* files. This directory is scanned recursively and all found **.unl* files will be converted.

Either **--src_topology_file** or **--src_dir** *must* be specified.
* **-d, --dst_dir** specifies destination folder. This is where the script will put generated GNS3 topologies. Default is **dst/**
* **-c, --console_start_port** specifies the first port for the console in GNS3. Default is 5000.
* **--l2_iol_image** specifies an L2 IOL image path in GNS3 if differs from EVE-NG.
* **--l3_iol_image** specifies an L3 IOL image path in GNS3 if differs from EVE-NG

Two options above may be useful if IOL images are named differently in EVE-NG and GNS3 or if completely different versions are imported in these two emulators.
This is implemented only for IOL. In future, there will be support of a mapping file, where you could specify mapping of image path/name in EVE-NG and corresponding image path/name in GNS3. Check #3

If the script does not work/crashes, please raise an issue.
6 changes: 3 additions & 3 deletions connections.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,11 @@ def build_gns_topology_json(self):
for i, interface in enumerate(self.interfaces):
node = interface.node
link_node_json = copy.deepcopy(json_templates.LINK_NODE_JSON_TEMPLATE)
adapter_number, port_number = interface.get_adapter_port_number()
if node.node_type == 'qemu':
link_node_json['adapter_number'] = port_number
link_node_json['port_number'] = adapter_number
link_node_json['adapter_number'] = interface.eve_id
link_node_json['port_number'] = 0
elif node.node_type == 'iol':
adapter_number, port_number = interface.get_adapter_port_number()
link_node_json['adapter_number'] = adapter_number
link_node_json['port_number'] = port_number
link_node_json['node_id'] = str(node.uuid)
Expand Down
40 changes: 22 additions & 18 deletions eve-to-gns3-converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ def get_arguments():
parsed ArgumentParser object
"""
parser = argparse.ArgumentParser()
parser.add_argument('-f', '--src_topology_file',
help='specify source UNL/EVE topology *.unl file',
type=argparse.FileType('r'))
parser.add_argument('-s', '--src_dir',
help='specify source folder containing *.unl files')
parser.add_argument('-d', '--dst_dir',
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('-f', '--src_topology_file',
help='specify source UNL/EVE topology *.unl file',
type=argparse.FileType('r'))
group.add_argument('-s', '--src_dir',
help='specify source folder containing *.unl files')
parser.add_argument('-d', '--dst_dir', default='dst/',
help='specify destination folder for resulting files')
parser.add_argument('-v', '--verbose', help='increase output verbosity',
action='store_true')
Expand All @@ -35,38 +36,41 @@ def get_arguments():
return args


def convert_topology(src_topology_file, args, src_dir=None):
if src_dir is not None:
path = pathlib.Path(src_dir)
dst_dir = args.dst_dir / path.relative_to(*path.parts[:1])
else:
dst_dir = args.dst_dir
topology = Topology(eve_xml=src_topology_file, args=args, dst_dir=dst_dir)
def convert_topology(src_topology_file, args, dst_dir):
# if src_dir is not None:
# path = pathlib.Path(src_dir)
# dst_dir = args.dst_dir / path.relative_to(*path.parts[:1])
# else:
# dst_dir = args.dst_dir
topology = Topology(src_topology_file, args, dst_dir)
topology.write_configs()
topology.write_gns_topology_json()


def main():
args = get_arguments()

if args.src_topology_file:
with args.src_topology_file as f:
src_topology_file = f.read()
convert_topology(src_topology_file, args)
convert_topology(src_topology_file, args, args.dst_dir)

elif args.src_dir:
count = 0
for root, dirs, files in os.walk(args.src_dir):
for dir_name, _, files in os.walk(args.src_dir):
relative_dir = os.path.relpath(dir_name, args.src_dir)
dst_dir = os.path.join(args.dst_dir, relative_dir)
for filename in files:
if filename.endswith(".unl"):
full_path = os.path.join(root, filename)
full_path = os.path.join(dir_name, filename)
print(f'Parsing {full_path}')
with open(full_path) as file:
src_topology_file = file.read()
convert_topology(src_topology_file, args, root)
convert_topology(src_topology_file, args, dst_dir)
count += 1

if not count:
print("No *.unl files have been found.")
raise FileNotFoundError("No *.unl files have been found.")


if __name__ == '__main__':
Expand Down
10 changes: 5 additions & 5 deletions node.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ def parse_interfaces(self, interfaces_dict):
"""
def parse_interface_dict(int_dict):
link_type = int_dict['@type']
eve_interface_id = int_dict['@id']
eve_interface_id = int(int_dict['@id'])
eve_interface_name = int_dict['@name']
try:
interface = self.get_interface(eve_interface_id)
Expand All @@ -177,7 +177,7 @@ def parse_interface_dict(int_dict):

elif link_type == 'serial':
eve_remote_node_id = int_dict['@remote_id']
eve_remote_interface_id = int_dict['@remote_if']
eve_remote_interface_id = int(int_dict['@remote_if'])
remote_node = self.topology.id_to_node.get(eve_remote_node_id)

if remote_node is None:
Expand Down Expand Up @@ -381,8 +381,8 @@ def __repr__(self):
return f'Interface(eve_id={self.eve_id}, eve_name={self.eve_name}, node={self.node})'

def get_adapter_port_number(self):
# if self.node.node_type == 'iol':
if self.node.node_type == 'iol':
parsed_values = INTERFACE_NAME_RE.match(self.eve_name).groupdict()
return int(parsed_values['adapter_number']), int(parsed_values['port_number'])
# else:
# raise NotImplementedError('This method is valid only for IOL devices')
else:
raise NotImplementedError('This method is valid only for IOL devices')
2 changes: 1 addition & 1 deletion topology.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class Topology(object):
GNS_SCENE_OFFSET = 200
GNS_DEFAULT_SCENE_SIZE = Size(2000, 1000)

def __init__(self, eve_xml=None, args=None, dst_dir=None):
def __init__(self, eve_xml, args, dst_dir='/dst'):
self.uuid = uuid.uuid4()
self.eve_xml = eve_xml
self.args = args
Expand Down

0 comments on commit 33b654c

Please sign in to comment.