├── .$output.xml.bkp
├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── drawio_network_plot.toml
├── drawio_network_plot
├── __init__.py
└── drawio_network_plot.py
├── examples
├── .DS_Store
├── cisco_gather_cdp_and_plot
│ ├── .DS_Store
│ ├── cisco_gather_cdp_and_plot.py
│ └── device_configurations
│ │ ├── Leaf_1
│ │ ├── Leaf_2
│ │ ├── Leaf_3
│ │ ├── Router_1
│ │ ├── Router_2
│ │ ├── Spine_1
│ │ └── Spine_2
├── example_1_output_snapshot.png
└── output.xml
├── icons
├── Firewall.png
├── L2_switch.png
├── L3_switch.png
├── Router.png
└── Server.png
├── output.xml
├── setup.py
├── test_temp.py
└── tests
├── __init__.py
└── unit_test.py
/.$output.xml.bkp:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | share/python-wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 | MANIFEST
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .nox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | *.py,cover
50 | .hypothesis/
51 | .pytest_cache/
52 | cover/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | .pybuilder/
76 | target/
77 |
78 | # Jupyter Notebook
79 | .ipynb_checkpoints
80 |
81 | # IPython
82 | profile_default/
83 | ipython_config.py
84 |
85 | # pyenv
86 | # For a library or package, you might want to ignore these files since the code is
87 | # intended to run in multiple environments; otherwise, check them in:
88 | # .python-version
89 |
90 | # pipenv
91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
94 | # install all needed dependencies.
95 | Pipfile.lock
96 |
97 | # poetry
98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99 | # This is especially recommended for binary packages to ensure reproducibility, and is more
100 | # commonly ignored for libraries.
101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102 | #poetry.lock
103 |
104 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
105 | __pypackages__/
106 |
107 | # Celery stuff
108 | celerybeat-schedule
109 | celerybeat.pid
110 |
111 | # SageMath parsed files
112 | *.sage.py
113 |
114 | # Environments
115 | .env
116 | .venv
117 | env/
118 | venv/
119 | ENV/
120 | env.bak/
121 | venv.bak/
122 |
123 | # Spyder project settings
124 | .spyderproject
125 | .spyproject
126 |
127 | # Rope project settings
128 | .ropeproject
129 |
130 | # mkdocs documentation
131 | /site
132 |
133 | # mypy
134 | .mypy_cache/
135 | .dmypy.json
136 | dmypy.json
137 |
138 | # Pyre type checker
139 | .pyre/
140 |
141 | # pytype static type analyzer
142 | .pytype/
143 |
144 | # Cython debug symbols
145 | cython_debug/
146 |
147 | # PyCharm
148 | # JetBrains specific template is maintainted in a separate JetBrains.gitignore that can
149 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
150 | # and can be added to the global gitignore or merged into this file. For a more nuclear
151 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
152 | #.idea/
153 |
154 | # General
155 | .DS_Store
156 | .AppleDouble
157 | .LSOverride
158 |
159 | # Icon must end with two \r
160 | Icon
161 |
162 | # Thumbnails
163 | ._*
164 |
165 | # Files that might appear in the root of a volume
166 | .DocumentRevisions-V100
167 | .fseventsd
168 | .Spotlight-V100
169 | .TemporaryItems
170 | .Trashes
171 | .VolumeIcon.icns
172 | .com.apple.timemachine.donotpresent
173 |
174 | # Directories potentially created on remote AFP share
175 | .AppleDB
176 | .AppleDesktop
177 | Network Trash Folder
178 | Temporary Items
179 | .apdisk
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Amr ElHusseiny
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # drawio_network_plot
2 | ## Overview
3 | - Package is mainly created for Network Automation , can be used in conjunction with other libraries to generate DrawIO plot for your Network (Service Provider ot Data Centter Network).
4 | - Available devices : Router , L3_Switch , L2_switch , Firewall , Server ( More to be added )
5 | - Output generated can be directly opened by DrawIO application (Desktop or Web version)
6 | ## Understanding the logic
7 | The "NetPlot" class is itself the plot , you initiate it and then you can do the following :
8 | - Add a Node or a Nodes list .
9 | - Add an Edge or a list of Edges .
10 | >Note : the edges has Source and Destination nodes , better to always put the Parent device in the Source node and the Child node in the Destination node , this will affect the way DrawIO does automatic Layouts .
11 | - After you open the file in DrawIO , you will see everything stacked on top of each other , simply go to "Arrange/Layout/Vertical Tree" and it will arrange the nodes and like the hirarichy of the Data center , you can also try out other layout options .
12 | ## Examples
13 | ### Example 1 : Datacenter Plot
14 | this example demonstrates how to use both the addition of object or list of objects at once :
15 | #### Code
16 | ```python
17 |
18 | from drawio_network_plot import NetPlot
19 |
20 | device_list = [
21 | # Routers
22 | {'nodeName' : 'Router_1','nodeType' : 'router','nodeDescription' : 'External Peering Provider 1'},
23 | {'nodeName' : 'Router_2','nodeType' : 'router','nodeDescription' : 'External Peering Provider 2'},
24 | # Core
25 | {'nodeName' : 'Core_switch_1','nodeType' : 'l3_switch','nodeDescription' : 'Spine Switch 01'},
26 | {'nodeName' : 'Core_switch_2','nodeType' : 'l3_switch','nodeDescription' : 'Spine Switch 02'},
27 | # Firewalls
28 | {'nodeName' : 'FW_1','nodeType' : 'firewall','nodeDescription' : 'Firewall 01'},
29 | {'nodeName' : 'FW_2','nodeType' : 'firewall','nodeDescription' : 'Firewall 02'},
30 | # Leafs
31 | {'nodeName' : 'TOR_1','nodeType' : 'l2_switch','nodeDescription' : 'Leaf Switch 01'},
32 | {'nodeName' : 'TOR_2','nodeType' : 'l2_switch','nodeDescription' : 'Leaf Switch 02'},
33 | {'nodeName' : 'TOR_3','nodeType' : 'l2_switch','nodeDescription' : 'Leaf Switch 03'},
34 | {'nodeName' : 'TOR_4','nodeType' : 'l2_switch','nodeDescription' : 'Leaf Switch 04'},
35 | # Servers
36 | {'nodeName' : 'Server_1','nodeType' : 'server','nodeDescription' : 'Server 1'},
37 | {'nodeName' : 'Server_2','nodeType' : 'server','nodeDescription' : 'Server 2'},
38 | {'nodeName' : 'Server_3','nodeType' : 'server','nodeDescription' : 'Server 3'},
39 | {'nodeName' : 'Server_4','nodeType' : 'server','nodeDescription' : 'Server 4'},
40 | {'nodeName' : 'Server_5','nodeType' : 'server','nodeDescription' : 'Server 5'},
41 | {'nodeName' : 'Server_6','nodeType' : 'server','nodeDescription' : 'Server 6'},
42 | {'nodeName' : 'Server_7','nodeType' : 'server','nodeDescription' : 'Server 7'},
43 | {'nodeName' : 'Server_8','nodeType' : 'server','nodeDescription' : 'Server 8'},
44 | {'nodeName' : 'Server_9','nodeType' : 'server','nodeDescription' : 'Server 9'},
45 | {'nodeName' : 'Server_10','nodeType' : 'server','nodeDescription' : 'Server 10'},
46 | {'nodeName' : 'Server_11','nodeType' : 'server','nodeDescription' : 'Server 11'},
47 | {'nodeName' : 'Server_12','nodeType' : 'server','nodeDescription' : 'Server 12'},
48 | {'nodeName' : 'Server_13','nodeType' : 'server','nodeDescription' : 'Server 13'},
49 | {'nodeName' : 'Server_14','nodeType' : 'server','nodeDescription' : 'Server 14'},
50 | {'nodeName' : 'Server_15','nodeType' : 'server','nodeDescription' : 'Server 15'},
51 | {'nodeName' : 'Server_16','nodeType' : 'server','nodeDescription' : 'Server 16'},
52 | ]
53 |
54 |
55 | connection_list = [
56 | # Router to Core
57 | {'sourceNodeID' : 'Router_1','destinationNodeID' : 'Core_switch_1'},
58 | {'sourceNodeID' : 'Router_1','destinationNodeID' : 'Core_switch_2'},
59 | {'sourceNodeID' : 'Router_2','destinationNodeID' : 'Core_switch_1'},
60 | {'sourceNodeID' : 'Router_2','destinationNodeID' : 'Core_switch_2'},
61 | # Core to FW
62 | {'sourceNodeID' : 'Core_switch_1','destinationNodeID' : 'FW_1'},
63 | {'sourceNodeID' : 'Core_switch_2','destinationNodeID' : 'FW_2'},
64 | # Core to TOR
65 | {'sourceNodeID' : 'Core_switch_1','destinationNodeID' : 'TOR_1'},
66 | {'sourceNodeID' : 'Core_switch_1','destinationNodeID' : 'TOR_2'},
67 | {'sourceNodeID' : 'Core_switch_1','destinationNodeID' : 'TOR_3'},
68 | {'sourceNodeID' : 'Core_switch_1','destinationNodeID' : 'TOR_4'},
69 | {'sourceNodeID' : 'Core_switch_2','destinationNodeID' : 'TOR_1'},
70 | {'sourceNodeID' : 'Core_switch_2','destinationNodeID' : 'TOR_2'},
71 | {'sourceNodeID' : 'Core_switch_2','destinationNodeID' : 'TOR_3'},
72 | {'sourceNodeID' : 'Core_switch_2','destinationNodeID' : 'TOR_4'},
73 | # TOR to Server
74 | {'sourceNodeID' : 'TOR_1','destinationNodeID' : 'Server_1'},
75 | {'sourceNodeID' : 'TOR_2','destinationNodeID' : 'Server_2'},
76 | {'sourceNodeID' : 'TOR_3','destinationNodeID' : 'Server_3'},
77 | {'sourceNodeID' : 'TOR_4','destinationNodeID' : 'Server_4'},
78 | {'sourceNodeID' : 'TOR_1','destinationNodeID' : 'Server_5'},
79 | {'sourceNodeID' : 'TOR_2','destinationNodeID' : 'Server_6'},
80 | {'sourceNodeID' : 'TOR_3','destinationNodeID' : 'Server_7'},
81 | {'sourceNodeID' : 'TOR_4','destinationNodeID' : 'Server_8'},
82 | {'sourceNodeID' : 'TOR_1','destinationNodeID' : 'Server_9'},
83 | {'sourceNodeID' : 'TOR_2','destinationNodeID' : 'Server_10'},
84 | {'sourceNodeID' : 'TOR_3','destinationNodeID' : 'Server_11'},
85 | {'sourceNodeID' : 'TOR_4','destinationNodeID' : 'Server_12'},
86 | {'sourceNodeID' : 'TOR_1','destinationNodeID' : 'Server_13'},
87 | {'sourceNodeID' : 'TOR_2','destinationNodeID' : 'Server_14'},
88 | {'sourceNodeID' : 'TOR_3','destinationNodeID' : 'Server_15'},
89 | {'sourceNodeID' : 'TOR_4','destinationNodeID' : 'Server_16'},
90 | ]
91 | # Initiating an Plot instance
92 | x = NetPlot()
93 | # Adding node by node and edge by edge
94 | x.addNode(nodeName='Router_17',nodeType='router')
95 | x.addNode(nodeName='Router_18',nodeType='router')
96 | # Adding lists of nodes and edges
97 | x.addLink('Router_17','Router_18')
98 | x.addLink('Router_17','Router_1')
99 | x.addNodeList(device_list)
100 | x.addLinkList(connection_list)
101 |
102 | # Output
103 | # 1- using method "display_xml"
104 | print(x.display_xml())
105 | # 2- printing the class will automatically call the "display_xml" method
106 | print(x)
107 | # 3- Exporting to XML file directly
108 | x.exportXML('examples/output.xml')
109 |
110 | ```
111 | #### Output
112 | 
--------------------------------------------------------------------------------
/drawio_network_plot.toml:
--------------------------------------------------------------------------------
1 | # drawio_network_plot.toml
2 |
3 | [build-system]
4 | requires = ["setuptools>=46.4.0", "wheel"]
5 | build-backend = "setuptools.build_meta"
--------------------------------------------------------------------------------
/drawio_network_plot/__init__.py:
--------------------------------------------------------------------------------
1 | # __init__.py
2 | from .drawio_network_plot import NetPlot
3 | #import drawio_network_plot
--------------------------------------------------------------------------------
/drawio_network_plot/drawio_network_plot.py:
--------------------------------------------------------------------------------
1 | import xml.etree.ElementTree as ET
2 | import logging
3 |
4 |
5 | class NetPlot():
6 | '''
7 | Creates the DrawIO Plot XML file , based on Jgraph template
8 | '''
9 | def __init__(self):
10 | # initiating the blocks needed for the DrawIO XML template , standard in every plot
11 | self.mxfile = ET.Element('mxfile',host="Electron",agent="5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/19.0.0 Chrome/100.0.4896.160 Electron/18.3.2 Safari/537.36",type="device")
12 | self.diagram = ET.SubElement(self.mxfile,'diagram',id="diagram_1",name="Page-1")
13 | self.mxGraphModel = ET.SubElement(self.diagram,
14 | 'mxGraphModel',
15 | grid="1",
16 | gridSize="10",
17 | guides="1",
18 | tooltips="1",
19 | connect="1",
20 | arrows="1",
21 | fold="1",
22 | page="1",
23 | pageScale="1",
24 | pageWidth="850",
25 | pageHeight="1100",
26 | math="0",
27 | shadow="0")
28 | self.root = ET.SubElement(self.mxGraphModel,'root')
29 | self.mxCellID0 = ET.SubElement(self.root,'mxCell' , id="0")
30 | # Each Node and Edge are a child to the Parent id "1"
31 | self.mxCellID1 = ET.SubElement(self.root,'mxCell' , id="1" , parent="0" , style=";html=1;")
32 |
33 | def _getMXgraphShape(self,nodeType):
34 | # Defining the shape that can be used , it uses shapes already shipped with DrawIO application (More shapes will be added)
35 | # we are also using the "nodeLevel" variable to set the hirarichy of the plot if standards are not adhered by in using library
36 | if nodeType == 'router':
37 | return {'style':'shape=mxgraph.cisco19.rect;prIcon=router;fillColor=#FAFAFA;strokeColor=#005073;html=1;',
38 | 'width':'50',
39 | 'height':'50',
40 | 'nodeLevel':'1'
41 | }
42 | elif nodeType == 'l2_switch':
43 | return {'style':'shape=mxgraph.cisco19.rect;prIcon=l2_switch;fillColor=#FAFAFA;strokeColor=#005073;html=1;',
44 | 'width':'50',
45 | 'height':'50',
46 | 'nodeLevel':'3'}
47 | elif nodeType == 'l3_switch':
48 | return {'style':'shape=mxgraph.cisco19.rect;prIcon=l3_switch;fillColor=#FAFAFA;strokeColor=#005073;html=1;',
49 | 'width':'50',
50 | 'height':'50',
51 | 'nodeLevel':'2'}
52 | elif nodeType == 'firewall':
53 | return {'style':'shape=mxgraph.cisco19.rect;prIcon=firewall;fillColor=#FAFAFA;strokeColor=#005073;html=1;',
54 | 'width':'64',
55 | 'height':'50',
56 | 'nodeLevel':'2'}
57 | elif nodeType == 'server':
58 | return {'style':'shape=mxgraph.cisco19.rect;prIcon=server;fillColor=#FAFAFA;strokeColor=#005073;html=1;',
59 | 'width':'27',
60 | 'height':'50',
61 | 'nodeLevel':'4'}
62 | else :
63 | return {'style':'shape=mxgraph.cisco19.rect;prIcon=server;fillColor=#FAFAFA;strokeColor=#005073;html=1;',
64 | 'width':'27',
65 | 'height':'50',
66 | 'nodeLevel':'4'}
67 |
68 |
69 | def addNode(self,nodeName,nodeDescription='',nodeType=''):
70 | try:
71 | shapeParameters = self._getMXgraphShape(nodeType)
72 | mxCell = ET.SubElement(self.root,
73 | 'mxCell',
74 | id=nodeName,
75 | value=nodeName,
76 | style=("verticalLabelPosition=bottom;"
77 | "html=1;"
78 | "verticalAlign=top;"
79 | "aspect=fixed;align=center;"
80 | "pointerEvents=1;"
81 | f"{shapeParameters['style']}"
82 | ""),
83 | parent="1",
84 | vertex="1")
85 | mxGeometry = ET.SubElement(mxCell, 'mxGeometry',width=shapeParameters['width'] ,height=shapeParameters['height'] )
86 | mxGeometry.set('as','geometry')
87 | return
88 | except Exception as e:
89 | logging.error('Error in adding Node: {}'.format(e))
90 |
91 | def addNodeList(self,nodeListOfDictionary):
92 | try:
93 | for node in nodeListOfDictionary:
94 | self.addNode(nodeName=node['nodeName'],nodeDescription=node['nodeDescription'],nodeType=node['nodeType'])
95 | return
96 | except Exception as e:
97 | logging.error('Error in adding Node List: {}'.format(e))
98 |
99 | def addLink(self,sourceNodeID,destinationNodeID):
100 | try:
101 | for mxCell in self.root:
102 | if mxCell.attrib['id'] == sourceNodeID:
103 | logging.debug('Source Node ID {} found'.format(sourceNodeID))
104 | break
105 | return
106 | except Exception as e:
107 | logging.error('Error in adding Link: {}'.format(e))
108 |
109 | mxCell = ET.SubElement(self.root,
110 | 'mxCell',
111 | id=sourceNodeID+destinationNodeID,
112 | style="endFill=0;endArrow=none;",
113 | parent="1",
114 | source=sourceNodeID,
115 | target=destinationNodeID,
116 | edge="1")
117 | mxGeometry = ET.SubElement(mxCell, 'mxGeometry')
118 | mxGeometry.set('as','geometry')
119 |
120 | def addLinkList(self,linkListOfDictionary):
121 | try:
122 | for link in linkListOfDictionary:
123 | self.addLink(sourceNodeID=link['sourceNodeID'] , destinationNodeID=link['destinationNodeID'] )
124 | return
125 | except Exception as e:
126 | logging.error('Error in adding Link List: {}'.format(e))
127 |
128 | def display_xml(self):
129 | return ET.tostring(self.mxfile)
130 |
131 | def exportXML(self, filePath):
132 | with open(filePath,'wb') as file:
133 | tree = ET.ElementTree(self.mxfile)
134 | tree.write(file)
135 | return
136 |
137 | def __repr__(self):
138 | return str(self.display_xml())
--------------------------------------------------------------------------------
/examples/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amrelhusseiny/drawio_network_plot/bfdeaf8648092aaba33dba458952b2a98c394f6b/examples/.DS_Store
--------------------------------------------------------------------------------
/examples/cisco_gather_cdp_and_plot/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amrelhusseiny/drawio_network_plot/bfdeaf8648092aaba33dba458952b2a98c394f6b/examples/cisco_gather_cdp_and_plot/.DS_Store
--------------------------------------------------------------------------------
/examples/cisco_gather_cdp_and_plot/cisco_gather_cdp_and_plot.py:
--------------------------------------------------------------------------------
1 | from netmiko import ConnectHandler
2 | import re
3 | from drawio_network_plot.drawio_network_plot import NetPlot
4 |
5 | # ----------------- Getting live CDP Neigbors to gather links endpoints ---------------------------
6 | def retieve_lldp_neigbor_hostname(devices_list):
7 | list_of_cdp_neighborship = []
8 | for device in devices_list:
9 | device_dictionary = {
10 | 'device_type': 'cisco_ios',
11 | 'host': device['ip_address'],
12 | 'username': 'automation',
13 | 'password' : '1234567',
14 | }
15 | net_connect = ConnectHandler(**device_dictionary)
16 | output = net_connect.send_command("show cdp neighbor")
17 | lines_list = output.splitlines()
18 | for line in lines_list:
19 | try:
20 | # regex to search the name of the device before the domain ID ".default" , then removing the word ".default" from the string
21 | link = {
22 | 'sourceNodeID' : device['nodeName'],
23 | 'destinationNodeID' : re.search('\S+\.default',line).group().replace('.default','')
24 | }
25 | # checking for duplication before adding new link :
26 | if {'sourceNodeID':link['destinationNodeID'],'destinationNodeID':link['sourceNodeID']} not in list_of_cdp_neighborship:
27 | list_of_cdp_neighborship.append(link)
28 | except:
29 | continue
30 | net_connect.disconnect()
31 | return list_of_cdp_neighborship
32 |
33 | def main():
34 | # Lab Devices , must have the device type for the plotting library to work
35 | devices = [
36 | {'nodeName':'Router_1','ip_address':'100.0.1.1','nodeType':'router','nodeDescription':'NA'},
37 | {'nodeName':'Router_2','ip_address':'100.0.1.2','nodeType':'router','nodeDescription':'NA'},
38 | {'nodeName':'Spine_1','ip_address':'100.0.2.1','nodeType':'l3_switch','nodeDescription':'NA'},
39 | {'nodeName':'Spine_2','ip_address':'100.0.2.2','nodeType':'l3_switch','nodeDescription':'NA'},
40 | {'nodeName':'Leaf_1','ip_address':'100.0.3.1','nodeType':'l2_switch','nodeDescription':'NA'},
41 | {'nodeName':'Leaf_2','ip_address':'100.0.3.2','nodeType':'l2_switch','nodeDescription':'NA'},
42 | {'nodeName':'Leaf_3','ip_address':'100.0.3.3','nodeType':'l2_switch','nodeDescription':'NA'}
43 | ]
44 | # Getting list of links for each device
45 | list_of_cdp_neighborship = retieve_lldp_neigbor_hostname(devices)
46 | for peering in list_of_cdp_neighborship:
47 | print(peering)
48 |
49 | # ------------------------------------------------------------------------------------------------------
50 | # ------------------------------------------------------------------------------------------------------
51 | # ----------------- Main Part : using library to generate XML DrawIIO format ---------------------------
52 | # Using the Plot library
53 | x = NetPlot()
54 | x.addNodeList(devices)
55 | x.addLinkList(list_of_cdp_neighborship)
56 |
57 | print(x.display_xml())
58 | # - You can also directly generate an XML file using the built in function :
59 | # x.exportXML('examples/output.xml')
60 | # - You can add node by node and connection by connection :
61 | # x.addNode(nodeName='Router_18',nodeType='router')
62 | # x.addLink('Router_17','Router_18')
63 | # ------------------------------------------------------------------------------------------------------
64 | # ------------------------------------------------------------------------------------------------------
65 | # ------------------------------------------------------------------------------------------------------
66 |
67 | if __name__ == "__main__":
68 | main()
--------------------------------------------------------------------------------
/examples/cisco_gather_cdp_and_plot/device_configurations/Leaf_1:
--------------------------------------------------------------------------------
1 | Leaf_1#sho running-config
2 | Building configuration...
3 |
4 | Current configuration : 1827 bytes
5 | !
6 | ! Last configuration change at 20:59:48 UTC Mon Sep 5 2022
7 | upgrade fpd auto
8 | version 15.3
9 | service timestamps debug datetime msec
10 | service timestamps log datetime msec
11 | no service password-encryption
12 | !
13 | hostname Leaf_1
14 | !
15 | boot-start-marker
16 | boot-end-marker
17 | !
18 | aqm-register-fnf
19 | !
20 | !
21 | aaa new-model
22 | aaa local authentication default authorization default
23 | !
24 | !
25 | aaa authentication login default local
26 | aaa authentication login automation local
27 | !
28 | !
29 | !
30 | !
31 | !
32 | aaa session-id common
33 | !
34 | !
35 | !
36 | !
37 | !
38 | !
39 | ip domain name default
40 | ip cef
41 | no ipv6 cef
42 | !
43 | multilink bundle-name authenticated
44 | !
45 | !
46 | !
47 | !
48 | !
49 | !
50 | !
51 | !
52 | !
53 | username automation password 0 1234567
54 | !
55 | redundancy
56 | !
57 | !
58 | !
59 | !
60 | !
61 | !
62 | !
63 | !
64 | !
65 | !
66 | !
67 | !
68 | interface Loopback100
69 | ip address 100.0.3.1 255.255.255.255
70 | ip ospf 1 area 0
71 | !
72 | interface FastEthernet0/0
73 | no ip address
74 | duplex full
75 | !
76 | interface Ethernet1/0
77 | no ip address
78 | duplex full
79 | !
80 | interface Ethernet1/1
81 | ip address 10.0.35.2 255.255.255.0
82 | ip ospf 1 area 0
83 | duplex full
84 | no shutdown
85 | !
86 | interface Ethernet1/2
87 | no ip address
88 | duplex full
89 | !
90 | interface Ethernet1/3
91 | no ip address
92 | duplex full
93 | !
94 | interface Ethernet1/4
95 | ip address 10.0.45.2 255.255.255.0
96 | ip ospf 1 area 0
97 | no shutdown
98 | duplex full
99 | !
100 | interface Ethernet1/5
101 | no ip address
102 | duplex full
103 | !
104 | interface Ethernet1/6
105 | no ip address
106 | duplex full
107 | !
108 | interface Ethernet1/7
109 | no ip address
110 | duplex full
111 | !
112 | router ospf 1
113 | router-id 100.0.3.1
114 | network 10.0.0.0 0.0.0.255 area 0
115 | !
116 | ip forward-protocol nd
117 | no ip http server
118 | no ip http secure-server
119 | !
120 | !
121 | ip route 0.0.0.0 0.0.0.0 192.168.1.1
122 | !
123 | !
124 | !
125 | !
126 | !
127 | !
128 | control-plane
129 | !
130 | !
131 | mgcp behavior rsip-range tgcp-only
132 | mgcp behavior comedia-role none
133 | mgcp behavior comedia-check-media-src disable
134 | mgcp behavior comedia-sdp-force disable
135 | !
136 | mgcp profile default
137 | !
138 | !
139 | !
140 | gatekeeper
141 | shutdown
142 | !
143 | !
144 | line con 0
145 | stopbits 1
146 | line aux 0
147 | stopbits 1
148 | line vty 0 4
149 | transport input all
150 | line vty 5 7
151 | transport input all
152 | !
153 | !
154 | end
155 |
156 | Leaf_1#
--------------------------------------------------------------------------------
/examples/cisco_gather_cdp_and_plot/device_configurations/Leaf_2:
--------------------------------------------------------------------------------
1 | Leaf_2#sho running-config
2 | Building configuration...
3 |
4 | Current configuration : 1817 bytes
5 | !
6 | ! Last configuration change at 21:00:11 UTC Mon Sep 5 2022
7 | upgrade fpd auto
8 | version 15.3
9 | service timestamps debug datetime msec
10 | service timestamps log datetime msec
11 | no service password-encryption
12 | !
13 | hostname Leaf_2
14 | !
15 | boot-start-marker
16 | boot-end-marker
17 | !
18 | aqm-register-fnf
19 | !
20 | !
21 | aaa new-model
22 | aaa local authentication default authorization default
23 | !
24 | !
25 | aaa authentication login default local
26 | aaa authentication login automation local
27 | !
28 | !
29 | !
30 | !
31 | !
32 | aaa session-id common
33 | !
34 | !
35 | !
36 | !
37 | !
38 | !
39 | ip domain name default
40 | ip cef
41 | no ipv6 cef
42 | !
43 | multilink bundle-name authenticated
44 | !
45 | !
46 | !
47 | !
48 | !
49 | !
50 | !
51 | !
52 | !
53 | username automation password 0 1234567
54 | !
55 | redundancy
56 | !
57 | !
58 | !
59 | !
60 | !
61 | !
62 | !
63 | !
64 | !
65 | !
66 | !
67 | !
68 | interface Loopback100
69 | ip address 100.0.3.2 255.255.255.255
70 | ip ospf 1 area 0
71 | !
72 | interface FastEthernet0/0
73 | no ip address
74 | duplex full
75 | !
76 | interface Ethernet1/0
77 | no ip address
78 | duplex full
79 | !
80 | interface Ethernet1/1
81 | no ip address
82 | duplex full
83 | !
84 | interface Ethernet1/2
85 | ip address 10.0.36.2 255.255.255.0
86 | ip ospf 1 area 0
87 | duplex full
88 | !
89 | interface Ethernet1/3
90 | no ip address
91 | duplex full
92 | !
93 | interface Ethernet1/4
94 | no ip address
95 | duplex full
96 | !
97 | interface Ethernet1/5
98 | ip address 10.0.46.2 255.255.255.0
99 | ip ospf 1 area 0
100 | duplex full
101 | !
102 | interface Ethernet1/6
103 | no ip address
104 | duplex full
105 | !
106 | interface Ethernet1/7
107 | no ip address
108 | duplex full
109 | !
110 | router ospf 1
111 | router-id 100.0.3.2
112 | network 10.0.0.0 0.0.0.255 area 0
113 | !
114 | ip forward-protocol nd
115 | no ip http server
116 | no ip http secure-server
117 | !
118 | !
119 | ip route 0.0.0.0 0.0.0.0 192.168.1.1
120 | !
121 | !
122 | !
123 | !
124 | !
125 | !
126 | control-plane
127 | !
128 | !
129 | mgcp behavior rsip-range tgcp-only
130 | mgcp behavior comedia-role none
131 | mgcp behavior comedia-check-media-src disable
132 | mgcp behavior comedia-sdp-force disable
133 | !
134 | mgcp profile default
135 | !
136 | !
137 | !
138 | gatekeeper
139 | shutdown
140 | !
141 | !
142 | line con 0
143 | stopbits 1
144 | line aux 0
145 | stopbits 1
146 | line vty 0 4
147 | transport input all
148 | line vty 5 7
149 | transport input all
150 | !
151 | !
152 | end
153 |
154 | Leaf_2#
--------------------------------------------------------------------------------
/examples/cisco_gather_cdp_and_plot/device_configurations/Leaf_3:
--------------------------------------------------------------------------------
1 | Leaf_3#show running-config
2 | Building configuration...
3 |
4 | Current configuration : 1817 bytes
5 | !
6 | ! Last configuration change at 21:00:39 UTC Mon Sep 5 2022
7 | upgrade fpd auto
8 | version 15.3
9 | service timestamps debug datetime msec
10 | service timestamps log datetime msec
11 | no service password-encryption
12 | !
13 | hostname Leaf_3
14 | !
15 | boot-start-marker
16 | boot-end-marker
17 | !
18 | aqm-register-fnf
19 | !
20 | !
21 | aaa new-model
22 | aaa local authentication default authorization default
23 | !
24 | !
25 | aaa authentication login default local
26 | aaa authentication login automation local
27 | !
28 | !
29 | !
30 | !
31 | !
32 | aaa session-id common
33 | !
34 | !
35 | !
36 | !
37 | !
38 | !
39 | ip domain name default
40 | ip cef
41 | no ipv6 cef
42 | !
43 | multilink bundle-name authenticated
44 | !
45 | !
46 | !
47 | !
48 | !
49 | !
50 | !
51 | !
52 | !
53 | username automation password 0 1234567
54 | !
55 | redundancy
56 | !
57 | !
58 | !
59 | !
60 | !
61 | !
62 | !
63 | !
64 | !
65 | !
66 | !
67 | !
68 | interface Loopback100
69 | ip address 100.0.3.3 255.255.255.255
70 | ip ospf 1 area 0
71 | !
72 | interface FastEthernet0/0
73 | no ip address
74 | duplex full
75 | !
76 | interface Ethernet1/0
77 | no ip address
78 | duplex full
79 | !
80 | interface Ethernet1/1
81 | no ip address
82 | duplex full
83 | !
84 | interface Ethernet1/2
85 | no ip address
86 | duplex full
87 | !
88 | interface Ethernet1/3
89 | ip address 10.0.37.2 255.255.255.0
90 | ip ospf 1 area 0
91 | duplex full
92 | !
93 | interface Ethernet1/4
94 | no ip address
95 | duplex full
96 | !
97 | interface Ethernet1/5
98 | no ip address
99 | duplex full
100 | !
101 | interface Ethernet1/6
102 | ip address 10.0.47.2 255.255.255.0
103 | ip ospf 1 area 0
104 | duplex full
105 | !
106 | interface Ethernet1/7
107 | no ip address
108 | duplex full
109 | !
110 | router ospf 1
111 | router-id 100.0.3.3
112 | network 10.0.0.0 0.0.0.255 area 0
113 | !
114 | ip forward-protocol nd
115 | no ip http server
116 | no ip http secure-server
117 | !
118 | !
119 | ip route 0.0.0.0 0.0.0.0 192.168.1.1
120 | !
121 | !
122 | !
123 | !
124 | !
125 | !
126 | control-plane
127 | !
128 | !
129 | mgcp behavior rsip-range tgcp-only
130 | mgcp behavior comedia-role none
131 | mgcp behavior comedia-check-media-src disable
132 | mgcp behavior comedia-sdp-force disable
133 | !
134 | mgcp profile default
135 | !
136 | !
137 | !
138 | gatekeeper
139 | shutdown
140 | !
141 | !
142 | line con 0
143 | stopbits 1
144 | line aux 0
145 | stopbits 1
146 | line vty 0 4
147 | transport input all
148 | line vty 5 7
149 | transport input all
150 | !
151 | !
152 | end
153 |
--------------------------------------------------------------------------------
/examples/cisco_gather_cdp_and_plot/device_configurations/Router_1:
--------------------------------------------------------------------------------
1 | Router_1#show running-config
2 | Building configuration...
3 |
4 | Current configuration : 2101 bytes
5 | !
6 | ! Last configuration change at 21:21:08 UTC Mon Sep 5 2022
7 | upgrade fpd auto
8 | version 15.3
9 | service timestamps debug datetime msec
10 | service timestamps log datetime msec
11 | no service password-encryption
12 | !
13 | hostname Router_1
14 | !
15 | boot-start-marker
16 | boot-end-marker
17 | !
18 | aqm-register-fnf
19 | !
20 | !
21 | aaa new-model
22 | aaa local authentication default authorization default
23 | !
24 | !
25 | aaa authentication login default local
26 | aaa authentication login automation local
27 | !
28 | !
29 | !
30 | !
31 | !
32 | aaa session-id common
33 | !
34 | !
35 | !
36 | !
37 | !
38 | !
39 | ip domain name default
40 | ip cef
41 | no ipv6 cef
42 | !
43 | multilink bundle-name authenticated
44 | !
45 | !
46 | !
47 | !
48 | !
49 | !
50 | !
51 | !
52 | !
53 | username automation password 0 1234567
54 | !
55 | redundancy
56 | !
57 | !
58 | !
59 | !
60 | !
61 | !
62 | !
63 | !
64 | !
65 | !
66 | !
67 | !
68 | interface Loopback100
69 | ip address 100.0.1.1 255.255.255.255
70 | ip ospf 1 area 0
71 | !
72 | interface FastEthernet0/0
73 | ip address 192.168.1.120 255.255.255.0
74 | ip nat outside
75 | ip virtual-reassembly in
76 | duplex full
77 | !
78 | interface Ethernet1/0
79 | ip address 10.0.13.1 255.255.255.0
80 | ip nat inside
81 | ip virtual-reassembly in
82 | ip ospf 1 area 0
83 | duplex full
84 | !
85 | interface Ethernet1/1
86 | no ip address
87 | duplex full
88 | !
89 | interface Ethernet1/2
90 | no ip address
91 | duplex full
92 | !
93 | interface Ethernet1/3
94 | no ip address
95 | duplex full
96 | !
97 | interface Ethernet1/4
98 | no ip address
99 | duplex full
100 | !
101 | interface Ethernet1/5
102 | no ip address
103 | duplex full
104 | !
105 | interface Ethernet1/6
106 | no ip address
107 | duplex full
108 | !
109 | interface Ethernet1/7
110 | no ip address
111 | duplex full
112 | !
113 | router ospf 1
114 | router-id 100.0.1.1
115 | network 10.0.0.0 0.0.0.255 area 0
116 | network 0.0.0.0 255.255.255.255 area 0
117 | !
118 | ip forward-protocol nd
119 | no ip http server
120 | no ip http secure-server
121 | !
122 | !
123 | ip nat inside source list 100 interface FastEthernet0/0 overload
124 | ip route 0.0.0.0 0.0.0.0 192.168.1.1
125 | !
126 | !
127 | !
128 | access-list 100 permit ip 10.0.0.0 0.255.255.255 any
129 | access-list 100 remark == [Control To Local Network]==
130 | !
131 | !
132 | !
133 | control-plane
134 | !
135 | !
136 | mgcp behavior rsip-range tgcp-only
137 | mgcp behavior comedia-role none
138 | mgcp behavior comedia-check-media-src disable
139 | mgcp behavior comedia-sdp-force disable
140 | !
141 | mgcp profile default
142 | !
143 | !
144 | !
145 | gatekeeper
146 | shutdown
147 | !
148 | !
149 | line con 0
150 | stopbits 1
151 | line aux 0
152 | stopbits 1
153 | line vty 0 4
154 | transport input all
155 | line vty 5 7
156 | transport input all
157 | !
158 | !
159 | end
160 |
--------------------------------------------------------------------------------
/examples/cisco_gather_cdp_and_plot/device_configurations/Router_2:
--------------------------------------------------------------------------------
1 | Router_2#show running-config
2 | Building configuration...
3 |
4 | Current configuration : 1819 bytes
5 | !
6 | ! Last configuration change at 20:58:19 UTC Mon Sep 5 2022 by automation
7 | upgrade fpd auto
8 | version 15.3
9 | service timestamps debug datetime msec
10 | service timestamps log datetime msec
11 | no service password-encryption
12 | !
13 | hostname Router_2
14 | !
15 | boot-start-marker
16 | boot-end-marker
17 | !
18 | aqm-register-fnf
19 | !
20 | !
21 | aaa new-model
22 | aaa local authentication default authorization default
23 | !
24 | !
25 | aaa authentication login default local
26 | aaa authentication login automation local
27 | !
28 | !
29 | !
30 | !
31 | !
32 | aaa session-id common
33 | !
34 | !
35 | !
36 | !
37 | !
38 | !
39 | ip domain name default
40 | ip cef
41 | no ipv6 cef
42 | !
43 | multilink bundle-name authenticated
44 | !
45 | !
46 | !
47 | !
48 | !
49 | !
50 | !
51 | !
52 | !
53 | username automation password 0 1234567
54 | !
55 | redundancy
56 | !
57 | !
58 | !
59 | !
60 | !
61 | !
62 | !
63 | !
64 | !
65 | !
66 | !
67 | !
68 | interface Loopback100
69 | ip address 100.0.1.2 255.255.255.255
70 | ip ospf 1 area 0
71 | !
72 | interface FastEthernet0/0
73 | ip address 192.168.1.121 255.255.255.0
74 | duplex full
75 | !
76 | interface Ethernet1/0
77 | ip address 10.0.24.1 255.255.255.0
78 | ip ospf 1 area 0
79 | duplex full
80 | !
81 | interface Ethernet1/1
82 | no ip address
83 | duplex full
84 | !
85 | interface Ethernet1/2
86 | no ip address
87 | duplex full
88 | !
89 | interface Ethernet1/3
90 | no ip address
91 | duplex full
92 | !
93 | interface Ethernet1/4
94 | no ip address
95 | duplex full
96 | !
97 | interface Ethernet1/5
98 | no ip address
99 | duplex full
100 | !
101 | interface Ethernet1/6
102 | no ip address
103 | duplex full
104 | !
105 | interface Ethernet1/7
106 | no ip address
107 | duplex full
108 | !
109 | router ospf 1
110 | router-id 100.0.1.2
111 | network 10.0.0.0 0.0.0.255 area 0
112 | !
113 | ip forward-protocol nd
114 | no ip http server
115 | no ip http secure-server
116 | !
117 | !
118 | ip route 0.0.0.0 0.0.0.0 192.168.1.1
119 | !
120 | !
121 | !
122 | !
123 | !
124 | !
125 | control-plane
126 | !
127 | !
128 | mgcp behavior rsip-range tgcp-only
129 | mgcp behavior comedia-role none
130 | mgcp behavior comedia-check-media-src disable
131 | mgcp behavior comedia-sdp-force disable
132 | !
133 | mgcp profile default
134 | !
135 | !
136 | !
137 | gatekeeper
138 | shutdown
139 | !
140 | !
141 | line con 0
142 | stopbits 1
143 | line aux 0
144 | stopbits 1
145 | line vty 0 4
146 | transport input all
147 | line vty 5 7
148 | transport input all
149 | !
150 | !
151 | end
152 |
153 | Router_2#
--------------------------------------------------------------------------------
/examples/cisco_gather_cdp_and_plot/device_configurations/Spine_1:
--------------------------------------------------------------------------------
1 | Spine_1#show running-config
2 | Building configuration...
3 |
4 | Current configuration : 1896 bytes
5 | !
6 | ! Last configuration change at 20:58:53 UTC Mon Sep 5 2022
7 | upgrade fpd auto
8 | version 15.3
9 | service timestamps debug datetime msec
10 | service timestamps log datetime msec
11 | no service password-encryption
12 | !
13 | hostname Spine_1
14 | !
15 | boot-start-marker
16 | boot-end-marker
17 | !
18 | aqm-register-fnf
19 | !
20 | !
21 | aaa new-model
22 | aaa local authentication default authorization default
23 | !
24 | !
25 | aaa authentication login default local
26 | aaa authentication login automation local
27 | !
28 | !
29 | !
30 | !
31 | !
32 | aaa session-id common
33 | !
34 | !
35 | !
36 | !
37 | !
38 | !
39 | ip domain name default
40 | ip cef
41 | no ipv6 cef
42 | !
43 | multilink bundle-name authenticated
44 | !
45 | !
46 | !
47 | !
48 | !
49 | !
50 | !
51 | !
52 | !
53 | username automation password 0 1234567
54 | !
55 | redundancy
56 | !
57 | !
58 | !
59 | !
60 | !
61 | !
62 | !
63 | !
64 | !
65 | !
66 | !
67 | !
68 | interface Loopback100
69 | ip address 100.0.2.1 255.255.255.255
70 | ip ospf 1 area 0
71 | !
72 | interface FastEthernet0/0
73 | no ip address
74 | duplex full
75 | !
76 | interface Ethernet1/0
77 | ip address 10.0.13.2 255.255.255.0
78 | ip ospf 1 area 0
79 | duplex full
80 | !
81 | interface Ethernet1/1
82 | ip address 10.0.35.1 255.255.255.0
83 | ip ospf 1 area 0
84 | duplex full
85 | !
86 | interface Ethernet1/2
87 | ip address 10.0.36.1 255.255.255.0
88 | ip ospf 1 area 0
89 | duplex full
90 | !
91 | interface Ethernet1/3
92 | ip address 10.0.37.1 255.255.255.0
93 | ip ospf 1 area 0
94 | duplex full
95 | !
96 | interface Ethernet1/4
97 | no ip address
98 | duplex full
99 | !
100 | interface Ethernet1/5
101 | no ip address
102 | duplex full
103 | !
104 | interface Ethernet1/6
105 | no ip address
106 | duplex full
107 | !
108 | interface Ethernet1/7
109 | no ip address
110 | duplex full
111 | !
112 | router ospf 1
113 | router-id 100.0.2.1
114 | network 10.0.0.0 0.0.0.255 area 0
115 | !
116 | ip forward-protocol nd
117 | no ip http server
118 | no ip http secure-server
119 | !
120 | !
121 | ip route 0.0.0.0 0.0.0.0 192.168.1.1
122 | !
123 | !
124 | !
125 | !
126 | !
127 | !
128 | control-plane
129 | !
130 | !
131 | mgcp behavior rsip-range tgcp-only
132 | mgcp behavior comedia-role none
133 | mgcp behavior comedia-check-media-src disable
134 | mgcp behavior comedia-sdp-force disable
135 | !
136 | mgcp profile default
137 | !
138 | !
139 | !
140 | gatekeeper
141 | shutdown
142 | !
143 | !
144 | line con 0
145 | stopbits 1
146 | line aux 0
147 | stopbits 1
148 | line vty 0 4
149 | transport input all
150 | line vty 5 7
151 | transport input all
152 | !
153 | !
154 | end
155 |
156 | Spine_1#
--------------------------------------------------------------------------------
/examples/cisco_gather_cdp_and_plot/device_configurations/Spine_2:
--------------------------------------------------------------------------------
1 | Spine_2#show running-config
2 | Building configuration...
3 |
4 | Current configuration : 1896 bytes
5 | !
6 | ! Last configuration change at 20:59:23 UTC Mon Sep 5 2022
7 | upgrade fpd auto
8 | version 15.3
9 | service timestamps debug datetime msec
10 | service timestamps log datetime msec
11 | no service password-encryption
12 | !
13 | hostname Spine_2
14 | !
15 | boot-start-marker
16 | boot-end-marker
17 | !
18 | aqm-register-fnf
19 | !
20 | !
21 | aaa new-model
22 | aaa local authentication default authorization default
23 | !
24 | !
25 | aaa authentication login default local
26 | aaa authentication login automation local
27 | !
28 | !
29 | !
30 | !
31 | !
32 | aaa session-id common
33 | !
34 | !
35 | !
36 | !
37 | !
38 | !
39 | ip domain name default
40 | ip cef
41 | no ipv6 cef
42 | !
43 | multilink bundle-name authenticated
44 | !
45 | !
46 | !
47 | !
48 | !
49 | !
50 | !
51 | !
52 | !
53 | username automation password 0 1234567
54 | !
55 | redundancy
56 | !
57 | !
58 | !
59 | !
60 | !
61 | !
62 | !
63 | !
64 | !
65 | !
66 | !
67 | !
68 | interface Loopback100
69 | ip address 100.0.2.2 255.255.255.255
70 | ip ospf 1 area 0
71 | !
72 | interface FastEthernet0/0
73 | no ip address
74 | duplex full
75 | !
76 | interface Ethernet1/0
77 | ip address 10.0.24.2 255.255.255.0
78 | ip ospf 1 area 0
79 | duplex full
80 | !
81 | interface Ethernet1/1
82 | no ip address
83 | duplex full
84 | !
85 | interface Ethernet1/2
86 | no ip address
87 | duplex full
88 | !
89 | interface Ethernet1/3
90 | no ip address
91 | duplex full
92 | !
93 | interface Ethernet1/4
94 | ip address 10.0.45.1 255.255.255.0
95 | ip ospf 1 area 0
96 | duplex full
97 | !
98 | interface Ethernet1/5
99 | ip address 10.0.46.1 255.255.255.0
100 | ip ospf 1 area 0
101 | duplex full
102 | !
103 | interface Ethernet1/6
104 | ip address 10.0.47.1 255.255.255.0
105 | ip ospf 1 area 0
106 | duplex full
107 | !
108 | interface Ethernet1/7
109 | no ip address
110 | duplex full
111 | !
112 | router ospf 1
113 | router-id 100.0.2.2
114 | network 10.0.0.0 0.0.0.255 area 0
115 | !
116 | ip forward-protocol nd
117 | no ip http server
118 | no ip http secure-server
119 | !
120 | !
121 | ip route 0.0.0.0 0.0.0.0 192.168.1.1
122 | !
123 | !
124 | !
125 | !
126 | !
127 | !
128 | control-plane
129 | !
130 | !
131 | mgcp behavior rsip-range tgcp-only
132 | mgcp behavior comedia-role none
133 | mgcp behavior comedia-check-media-src disable
134 | mgcp behavior comedia-sdp-force disable
135 | !
136 | mgcp profile default
137 | !
138 | !
139 | !
140 | gatekeeper
141 | shutdown
142 | !
143 | !
144 | line con 0
145 | stopbits 1
146 | line aux 0
147 | stopbits 1
148 | line vty 0 4
149 | transport input all
150 | line vty 5 7
151 | transport input all
152 | !
153 | !
154 | end
155 |
156 | Spine_2#
--------------------------------------------------------------------------------
/examples/example_1_output_snapshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amrelhusseiny/drawio_network_plot/bfdeaf8648092aaba33dba458952b2a98c394f6b/examples/example_1_output_snapshot.png
--------------------------------------------------------------------------------
/examples/output.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/icons/Firewall.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amrelhusseiny/drawio_network_plot/bfdeaf8648092aaba33dba458952b2a98c394f6b/icons/Firewall.png
--------------------------------------------------------------------------------
/icons/L2_switch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amrelhusseiny/drawio_network_plot/bfdeaf8648092aaba33dba458952b2a98c394f6b/icons/L2_switch.png
--------------------------------------------------------------------------------
/icons/L3_switch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amrelhusseiny/drawio_network_plot/bfdeaf8648092aaba33dba458952b2a98c394f6b/icons/L3_switch.png
--------------------------------------------------------------------------------
/icons/Router.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amrelhusseiny/drawio_network_plot/bfdeaf8648092aaba33dba458952b2a98c394f6b/icons/Router.png
--------------------------------------------------------------------------------
/icons/Server.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amrelhusseiny/drawio_network_plot/bfdeaf8648092aaba33dba458952b2a98c394f6b/icons/Server.png
--------------------------------------------------------------------------------
/output.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | # setup.py
2 |
3 | from setuptools import setup, find_packages
4 |
5 | VERSION = '0.0.1'
6 | DESCRIPTION = 'Plot Network using python , and output to DrawIO file'
7 |
8 | with open('README.md') as readme_file:
9 | LONG_DESCRIPTION = readme_file.read()
10 |
11 | # Setting up
12 | setup(
13 | # the name must match the folder name 'verysimplemodule'
14 | name="drawio_network_plot",
15 | version="0.0.02 Beta",
16 | author="Amr ElHusseiny",
17 | author_email="amroashram@hotmail.com",
18 | description=DESCRIPTION,
19 | long_description= LONG_DESCRIPTION ,
20 | long_description_content_type='text/markdown',
21 | packages=find_packages(),
22 | install_requires=[], # No packages needed - all standard libraries
23 | keywords=['python', 'first package'],
24 | classifiers= ['Development Status :: 4 - Beta','Topic :: System :: Networking'],
25 | python_requires='>=3.6',
26 | )
--------------------------------------------------------------------------------
/test_temp.py:
--------------------------------------------------------------------------------
1 | from drawio_network_plot.drawio_network_plot import NetPlot
2 |
3 | device_list = [
4 | # Routers
5 | {'nodeName' : 'Router_1','nodeType' : 'router','nodeDescription' : 'External Peering Provider 1'},
6 | {'nodeName' : 'Router_2','nodeType' : 'router','nodeDescription' : 'External Peering Provider 2'},
7 | # Core
8 | {'nodeName' : 'Core_switch_1','nodeType' : 'l3_switch','nodeDescription' : 'Spine Switch 01'},
9 | {'nodeName' : 'Core_switch_2','nodeType' : 'l3_switch','nodeDescription' : 'Spine Switch 02'},
10 | # Firewalls
11 | {'nodeName' : 'FW_1','nodeType' : 'firewall','nodeDescription' : 'Firewall 01'},
12 | {'nodeName' : 'FW_2','nodeType' : 'firewall','nodeDescription' : 'Firewall 02'},
13 | # Leafs
14 | {'nodeName' : 'TOR_1','nodeType' : 'l2_switch','nodeDescription' : 'Leaf Switch 01'},
15 | {'nodeName' : 'TOR_2','nodeType' : 'l2_switch','nodeDescription' : 'Leaf Switch 02'},
16 | {'nodeName' : 'TOR_3','nodeType' : 'l2_switch','nodeDescription' : 'Leaf Switch 03'},
17 | {'nodeName' : 'TOR_4','nodeType' : 'l2_switch','nodeDescription' : 'Leaf Switch 04'},
18 | # Servers
19 | {'nodeName' : 'Server_1','nodeType' : 'server','nodeDescription' : 'Server 1'},
20 | {'nodeName' : 'Server_2','nodeType' : 'server','nodeDescription' : 'Server 2'},
21 | {'nodeName' : 'Server_3','nodeType' : 'server','nodeDescription' : 'Server 3'},
22 | {'nodeName' : 'Server_4','nodeType' : 'server','nodeDescription' : 'Server 4'},
23 | {'nodeName' : 'Server_5','nodeType' : 'server','nodeDescription' : 'Server 5'},
24 | {'nodeName' : 'Server_6','nodeType' : 'server','nodeDescription' : 'Server 6'},
25 | {'nodeName' : 'Server_7','nodeType' : 'server','nodeDescription' : 'Server 7'},
26 | {'nodeName' : 'Server_8','nodeType' : 'server','nodeDescription' : 'Server 8'},
27 | {'nodeName' : 'Server_9','nodeType' : 'server','nodeDescription' : 'Server 9'},
28 | {'nodeName' : 'Server_10','nodeType' : 'server','nodeDescription' : 'Server 10'},
29 | {'nodeName' : 'Server_11','nodeType' : 'server','nodeDescription' : 'Server 11'},
30 | {'nodeName' : 'Server_12','nodeType' : 'server','nodeDescription' : 'Server 12'},
31 | {'nodeName' : 'Server_13','nodeType' : 'server','nodeDescription' : 'Server 13'},
32 | {'nodeName' : 'Server_14','nodeType' : 'server','nodeDescription' : 'Server 14'},
33 | {'nodeName' : 'Server_15','nodeType' : 'server','nodeDescription' : 'Server 15'},
34 | {'nodeName' : 'Server_16','nodeType' : 'server','nodeDescription' : 'Server 16'},
35 | ]
36 |
37 |
38 | connection_list = [
39 | # Router to Core
40 | {'sourceNodeID' : 'Router_1','destinationNodeID' : 'Core_switch_1'},
41 | {'sourceNodeID' : 'Router_1','destinationNodeID' : 'Core_switch_2'},
42 | {'sourceNodeID' : 'Router_2','destinationNodeID' : 'Core_switch_1'},
43 | {'sourceNodeID' : 'Router_2','destinationNodeID' : 'Core_switch_2'},
44 | # Core to FW
45 | {'sourceNodeID' : 'Core_switch_1','destinationNodeID' : 'FW_1'},
46 | {'sourceNodeID' : 'Core_switch_2','destinationNodeID' : 'FW_2'},
47 | # Core to TOR
48 | {'sourceNodeID' : 'Core_switch_1','destinationNodeID' : 'TOR_1'},
49 | {'sourceNodeID' : 'Core_switch_1','destinationNodeID' : 'TOR_2'},
50 | {'sourceNodeID' : 'Core_switch_1','destinationNodeID' : 'TOR_3'},
51 | {'sourceNodeID' : 'Core_switch_1','destinationNodeID' : 'TOR_4'},
52 | {'sourceNodeID' : 'Core_switch_2','destinationNodeID' : 'TOR_1'},
53 | {'sourceNodeID' : 'Core_switch_2','destinationNodeID' : 'TOR_2'},
54 | {'sourceNodeID' : 'Core_switch_2','destinationNodeID' : 'TOR_3'},
55 | {'sourceNodeID' : 'Core_switch_2','destinationNodeID' : 'TOR_4'},
56 | # TOR to Server
57 | {'sourceNodeID' : 'TOR_1','destinationNodeID' : 'Server_1'},
58 | {'sourceNodeID' : 'TOR_2','destinationNodeID' : 'Server_2'},
59 | {'sourceNodeID' : 'TOR_3','destinationNodeID' : 'Server_3'},
60 | {'sourceNodeID' : 'TOR_4','destinationNodeID' : 'Server_4'},
61 | {'sourceNodeID' : 'TOR_1','destinationNodeID' : 'Server_5'},
62 | {'sourceNodeID' : 'TOR_2','destinationNodeID' : 'Server_6'},
63 | {'sourceNodeID' : 'TOR_3','destinationNodeID' : 'Server_7'},
64 | {'sourceNodeID' : 'TOR_4','destinationNodeID' : 'Server_8'},
65 | {'sourceNodeID' : 'TOR_1','destinationNodeID' : 'Server_9'},
66 | {'sourceNodeID' : 'TOR_2','destinationNodeID' : 'Server_10'},
67 | {'sourceNodeID' : 'TOR_3','destinationNodeID' : 'Server_11'},
68 | {'sourceNodeID' : 'TOR_4','destinationNodeID' : 'Server_12'},
69 | {'sourceNodeID' : 'TOR_1','destinationNodeID' : 'Server_13'},
70 | {'sourceNodeID' : 'TOR_2','destinationNodeID' : 'Server_14'},
71 | {'sourceNodeID' : 'TOR_3','destinationNodeID' : 'Server_15'},
72 | {'sourceNodeID' : 'TOR_4','destinationNodeID' : 'Server_16'},
73 | ]
74 | x = NetPlot()
75 | x.addNode(nodeName='Router_17',nodeType='router')
76 | x.addNode(nodeName='Router_18',nodeType='router')
77 | x.addLink('Router_17','Router_18')
78 | x.addLink('Router_17','Router_1')
79 | x.addNodeList(device_list)
80 | x.addLinkList(connection_list)
81 | # print(x.display_xml())
82 | # print(x)
83 | x.exportXML('examples/output.xml')
84 | # for mxCell in x.root:
85 | # print(item.get('value'))
86 | # print(item.get('id'))
87 | # print(mxCell.attrib)
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
1 | # __init__.py
--------------------------------------------------------------------------------
/tests/unit_test.py:
--------------------------------------------------------------------------------
1 | from drawio_network_plot import NetPlot
2 |
3 | device_list = [
4 | # Routers
5 | {'nodeName' : 'Router_1','nodeType' : 'router','nodeDescription' : 'External Peering Provider 1'},
6 | {'nodeName' : 'Router_2','nodeType' : 'router','nodeDescription' : 'External Peering Provider 2'},
7 | # Core
8 | {'nodeName' : 'Core_switch_1','nodeType' : 'l3_switch','nodeDescription' : 'Spine Switch 01'},
9 | {'nodeName' : 'Core_switch_2','nodeType' : 'l3_switch','nodeDescription' : 'Spine Switch 02'},
10 | # Firewalls
11 | {'nodeName' : 'FW_1','nodeType' : 'firewall','nodeDescription' : 'Firewall 01'},
12 | {'nodeName' : 'FW_2','nodeType' : 'firewall','nodeDescription' : 'Firewall 02'},
13 | # Leafs
14 | {'nodeName' : 'TOR_1','nodeType' : 'l2_switch','nodeDescription' : 'Leaf Switch 01'},
15 | {'nodeName' : 'TOR_2','nodeType' : 'l2_switch','nodeDescription' : 'Leaf Switch 02'},
16 | {'nodeName' : 'TOR_3','nodeType' : 'l2_switch','nodeDescription' : 'Leaf Switch 03'},
17 | {'nodeName' : 'TOR_4','nodeType' : 'l2_switch','nodeDescription' : 'Leaf Switch 04'},
18 | # Servers
19 | {'nodeName' : 'Server_1','nodeType' : 'server','nodeDescription' : 'Server 1'},
20 | {'nodeName' : 'Server_2','nodeType' : 'server','nodeDescription' : 'Server 2'},
21 | {'nodeName' : 'Server_3','nodeType' : 'server','nodeDescription' : 'Server 3'},
22 | {'nodeName' : 'Server_4','nodeType' : 'server','nodeDescription' : 'Server 4'},
23 | {'nodeName' : 'Server_5','nodeType' : 'server','nodeDescription' : 'Server 5'},
24 | {'nodeName' : 'Server_6','nodeType' : 'server','nodeDescription' : 'Server 6'},
25 | {'nodeName' : 'Server_7','nodeType' : 'server','nodeDescription' : 'Server 7'},
26 | {'nodeName' : 'Server_8','nodeType' : 'server','nodeDescription' : 'Server 8'},
27 | {'nodeName' : 'Server_9','nodeType' : 'server','nodeDescription' : 'Server 9'},
28 | {'nodeName' : 'Server_10','nodeType' : 'server','nodeDescription' : 'Server 10'},
29 | {'nodeName' : 'Server_11','nodeType' : 'server','nodeDescription' : 'Server 11'},
30 | {'nodeName' : 'Server_12','nodeType' : 'server','nodeDescription' : 'Server 12'},
31 | {'nodeName' : 'Server_13','nodeType' : 'server','nodeDescription' : 'Server 13'},
32 | {'nodeName' : 'Server_14','nodeType' : 'server','nodeDescription' : 'Server 14'},
33 | {'nodeName' : 'Server_15','nodeType' : 'server','nodeDescription' : 'Server 15'},
34 | {'nodeName' : 'Server_16','nodeType' : 'server','nodeDescription' : 'Server 16'},
35 | ]
36 |
37 |
38 | connection_list = [
39 | # Router to Core
40 | {'sourceNodeID' : 'Router_1','destinationNodeID' : 'Core_switch_1'},
41 | {'sourceNodeID' : 'Router_1','destinationNodeID' : 'Core_switch_2'},
42 | {'sourceNodeID' : 'Router_2','destinationNodeID' : 'Core_switch_1'},
43 | {'sourceNodeID' : 'Router_2','destinationNodeID' : 'Core_switch_2'},
44 | # Core to FW
45 | {'sourceNodeID' : 'Core_switch_1','destinationNodeID' : 'FW_1'},
46 | {'sourceNodeID' : 'Core_switch_2','destinationNodeID' : 'FW_2'},
47 | # Core to TOR
48 | {'sourceNodeID' : 'Core_switch_1','destinationNodeID' : 'TOR_1'},
49 | {'sourceNodeID' : 'Core_switch_1','destinationNodeID' : 'TOR_2'},
50 | {'sourceNodeID' : 'Core_switch_1','destinationNodeID' : 'TOR_3'},
51 | {'sourceNodeID' : 'Core_switch_1','destinationNodeID' : 'TOR_4'},
52 | {'sourceNodeID' : 'Core_switch_2','destinationNodeID' : 'TOR_1'},
53 | {'sourceNodeID' : 'Core_switch_2','destinationNodeID' : 'TOR_2'},
54 | {'sourceNodeID' : 'Core_switch_2','destinationNodeID' : 'TOR_3'},
55 | {'sourceNodeID' : 'Core_switch_2','destinationNodeID' : 'TOR_4'},
56 | # TOR to Server
57 | {'sourceNodeID' : 'TOR_1','destinationNodeID' : 'Server_1'},
58 | {'sourceNodeID' : 'TOR_2','destinationNodeID' : 'Server_2'},
59 | {'sourceNodeID' : 'TOR_3','destinationNodeID' : 'Server_3'},
60 | {'sourceNodeID' : 'TOR_4','destinationNodeID' : 'Server_4'},
61 | {'sourceNodeID' : 'TOR_1','destinationNodeID' : 'Server_5'},
62 | {'sourceNodeID' : 'TOR_2','destinationNodeID' : 'Server_6'},
63 | {'sourceNodeID' : 'TOR_3','destinationNodeID' : 'Server_7'},
64 | {'sourceNodeID' : 'TOR_4','destinationNodeID' : 'Server_8'},
65 | {'sourceNodeID' : 'TOR_1','destinationNodeID' : 'Server_9'},
66 | {'sourceNodeID' : 'TOR_2','destinationNodeID' : 'Server_10'},
67 | {'sourceNodeID' : 'TOR_3','destinationNodeID' : 'Server_11'},
68 | {'sourceNodeID' : 'TOR_4','destinationNodeID' : 'Server_12'},
69 | {'sourceNodeID' : 'TOR_1','destinationNodeID' : 'Server_13'},
70 | {'sourceNodeID' : 'TOR_2','destinationNodeID' : 'Server_14'},
71 | {'sourceNodeID' : 'TOR_3','destinationNodeID' : 'Server_15'},
72 | {'sourceNodeID' : 'TOR_4','destinationNodeID' : 'Server_16'},
73 | ]
74 | x = NetPlot()
75 | x.addNode(nodeName='Router_17',nodeType='router')
76 | x.addNode(nodeName='Router_18',nodeType='router')
77 | x.addLink('Router_17','Router_18')
78 | x.addLink('Router_17','Router_1')
79 | x.addNodeList(device_list)
80 | x.addLinkList(connection_list)
81 | # print(x.display_xml())
82 | # print(x)
83 | x.exportXML('examples/output.xml')
84 | for mxCell in x.root:
85 | # print(item.get('value'))
86 | # print(item.get('id'))
87 | print(mxCell.attrib)
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------