Overview
Much of the time invested as a Network Engineer is performing network simulations for reasons like studying for a certification, trying out a proof-of-concept or testing design patterns, or even validate configuration changes before pushing to production!
One of the best platforms out there for network device simulation is GNS3, which stands for Graphical Network Simulator-3. It is commonly implemented with a GNS3 server ,where the network nodes simulations, topology and projects are stored and processed, and a GUI application on the user computer to interact with it.
The GNS3 server provides a really good REST API that we can leverage for programability purposes.
In this post I will write about gns3fy, a python interface of the GNS3 server and its elements that is easy and reliable to use. Network engineers can use it for multiple purposes like creating scripts, use it in automated pipelines (CI/CD systems) or even local testing.
Installation and requirements
It can be installed using pip
:
pip install gns3fy
You also need to have successful connection with the GNS3 server REST API where your project is located. In this example I will use a remote server:
- Server URL:
http://dev-gn3server
- Port:
3080
- Lab name (project in GNS3):
test_lab
Main objects of the library
The library exports 4 main objects for you to interact with:
Gns3Connector
: Is a connector type object that performs the main HTTP transactions and operations against the server REST APIProject
: Interacts with a specific GNS3 projectNode
: Interacts with a specific node of a projectLink
: Interacts with a specific link of a project
For more information you can take a look at the API Reference - gns3fy
Connect to the server and collect the project
Ok, enough of introductions and let’s get down to it. First we need to define a connector object and a project object from it.
from gns3fy import Gns3Connector, Project, Node, Link
SERVER_URL = "http://dev-gns3server:3080"
# Define the connector object, by default its port is 3080
server = Gns3Connector(url=SERVER_URL)
# Verify connectivity by checking the server version
print(server.get_verion())
{'local': False, 'version': '2.2.0b4'}
# Now obtain a project from the server
lab = Project(name="test_lab", connector=server)
lab.get()
# Show some of its attributes
print(f"{lab.name}: {lab.id} -- Status {lab.status}")
# test_lab: 4b21dfb3-675a-4efa-8613-2f7fb32e76f -- Status: closed
Lets open it
lab.open()
print(lab.status)
# opened
Now we can interact with the topology inside it.
Turning up the nodes
You can verify the nodes inside a project under the attribute lab.nodes
, which gives a list of the Node
(s) objects available . There is also a handy method you can use to list a summary of nodes inside a project:
print(lab.nodes_summary())
# veos-1: stopped -- Console: 5028 -- ID: ea3a788d-51ee-4efb-a7aa-02db682999ac
# veos-2: stopped -- Console: 5030 -- ID: c3b87554-72b6-4c21-b7d4-0b4679f192e8
We have 2 nodes. Lets start them up with a delay of 30 seconds between them (this is usually good for large scenarios or devices that take up too much resources when booting up)
import time
for node in lab.nodes:
node.start()
time.sleep(30)
# Now check again the status of the nodes
lab.get_nodes()
print(lab.nodes_summary())
# veos-1: started -- Console: 5028 -- ID: ea3a788d-51ee-4efb-a7aa-02db682999ac
# veos-2: started -- Console: 5030 -- ID: c3b87554-72b6-4c21-b7d4-0b4679f192e8
Node properties
Each nodes and link on a project has its own properties and attributes. For example you can inspect an specific node and retrieve its properties:
from pprint import pprint
veos1 = lab.get_node("veos-1")
pprint(veos1.properties)
# {'adapter_type': 'e1000',
# 'adapters': 13,
# 'category': 'router',
# 'console_type': 'telnet',
# 'cpu_throttling': 0,
# 'cpus': 2,
# 'custom_adapters': [],
# 'first_port_name': 'Management1',
# 'hda_disk_image': 'vEOS-lab-4.21.5F.vmdk',
# ...
# To verify its ports
pprint(veos1.ports)
# [{'adapter_number': 0,
# 'adapter_type': 'e1000',
# 'data_link_types': {'Ethernet': 'DLT_EN10MB'},
# 'link_type': 'ethernet',
# 'mac_address': '0c:53:2e:99:ac:00',
# 'name': 'Ethernet0',
# 'port_number': 0,
# 'short_name': 'e0'},
# ...
Creating a link
Now let’s get a feel of how the links are set up in the project. For this we can use the links_summary
method
print(lab.links_summary())
# veos-1: Ethernet1 ---- veos-2: Ethernet1
Ok, so let’s try creating another link between the nodes
lab.create_link("veos-1", "Ethernet1", "veos-2", "Ethernet3")
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-25-c5afeaa1b3bc> in <module>
----> 1 lab.create_link("veos-1", "Ethernet1", "veos-2", "Ethernet3")
~/miniconda3/envs/ansible-netsetup/lib/python3.7/site-packages/gns3fy/gns3fy.py in create_link(self, node_a, port_a, node_b, port_b)
1446 _matches.append(_l)
1447 if _matches:
-> 1448 raise ValueError(f"At least one port is used, ID: {_matches[0].link_id}")
1449
1450 # Now create the link!
ValueError: At least one port is used, ID: ab81059b-b454-490a-914f-535a898a281c
Oops, I had a typo and port veos-1 Ethernet1
is already used. Let’s fix that
lab.create_link("veos-1", "Ethernet3", "veos-2", "Ethernet3")
# Created Link-ID: d583f011-6d52-4871-a37b-fcc5a44ee76b -- Type: ethernet
# Now lets verify all the links
lab.links_summary()
# veos-1: Ethernet1 ---- veos-2: Ethernet1
# veos-1: Ethernet3 ---- veos-2: Ethernet3
Great! we have successfully created a link on the project.
I hope you have seen how easy is to interact with the GNS3 server REST API using gns3fy!