diff --git a/N2G/plugins/data/cli_l2_data.py b/N2G/plugins/data/cli_l2_data.py index 8036cf9..bd11c03 100644 --- a/N2G/plugins/data/cli_l2_data.py +++ b/N2G/plugins/data/cli_l2_data.py @@ -66,7 +66,7 @@ huawei: * ``display lldp neighbor details`` - mandatory -* ``display current-configuration`` - optional, used for LAG and interfaces config +* ``display current-configuration interface`` - optional, used for LAG and interfaces config * ``display interface`` - optional, used for interfaces state and to add all connected nodes juniper: diff --git a/N2G/plugins/data/xlsx_data.py b/N2G/plugins/data/xlsx_data.py index 128dc3e..d40f6bc 100644 --- a/N2G/plugins/data/xlsx_data.py +++ b/N2G/plugins/data/xlsx_data.py @@ -109,7 +109,7 @@ try: from openpyxl import load_workbook except ImportError: - log.error("Failed to import openpyxl module") + log.debug("N2G xlsx data plugin failed to import openpyxl module") def translate_headers(headers, translate_dict): diff --git a/N2G/plugins/diagrams/N2G_DrawIO.py b/N2G/plugins/diagrams/N2G_DrawIO.py index 466e024..533519d 100644 --- a/N2G/plugins/diagrams/N2G_DrawIO.py +++ b/N2G/plugins/diagrams/N2G_DrawIO.py @@ -421,15 +421,14 @@ def dump_file(self, filename=None, folder="./Output/"): """ import time - # check output folder, if not exists, create it - if not os.path.exists(folder): - os.makedirs(folder) + # create output folder if it does not exists + os.makedirs(folder, exist_ok=True) # create file name if not filename: ctime = time.ctime().replace(":", "-") filename = "{}_output.drawio".format(ctime) # save file to disk - with open(folder + filename, "w") as outfile: + with open(os.path.join(folder, filename), "w") as outfile: outfile.write(self.dump_xml()) def layout(self, algo="kk", **kwargs): diff --git a/N2G/plugins/diagrams/N2G_V3D.py b/N2G/plugins/diagrams/N2G_V3D.py index a872c32..8ab6954 100644 --- a/N2G/plugins/diagrams/N2G_V3D.py +++ b/N2G/plugins/diagrams/N2G_V3D.py @@ -502,15 +502,14 @@ def dump_file(self, filename=None, folder="./Output/", json_kwargs=None): import time json_kwargs = json_kwargs or {"sort_keys": True, "indent": 4} - # check output folder, if not exists, create it - if not os.path.exists(folder): - os.makedirs(folder) + # create output folder if it does not exists + os.makedirs(folder, exist_ok=True) # create file name if not filename: ctime = time.ctime().replace(":", "-") filename = "{}_output.txt".format(ctime) # save file to disk - with open(folder + filename, "w") as outfile: + with open(os.path.join(folder, filename), "w") as outfile: outfile.write(self.dump_json(**json_kwargs)) def run( diff --git a/N2G/plugins/diagrams/N2G_yEd.py b/N2G/plugins/diagrams/N2G_yEd.py index f698d05..2e06d1d 100644 --- a/N2G/plugins/diagrams/N2G_yEd.py +++ b/N2G/plugins/diagrams/N2G_yEd.py @@ -951,15 +951,14 @@ def dump_file(self, filename=None, folder="./Output/"): import os import time - # check output folder, if not exists, create it - if not os.path.exists(folder): - os.makedirs(folder) + # create output folder if it does not exists + os.makedirs(folder, exist_ok=True) # create file name if not filename: ctime = time.ctime().replace(":", "-") filename = "{}_output.graphml".format(ctime) # save file to disk - with open(folder + filename, "w") as outfile: + with open(os.path.join(folder, filename), "w") as outfile: outfile.write(self.dump_xml()) def set_attributes( diff --git a/N2G/plugins/viewers/v3d_viewer/v3d_viewer.py b/N2G/plugins/viewers/v3d_viewer/v3d_viewer.py index ae1162b..94e658c 100644 --- a/N2G/plugins/viewers/v3d_viewer/v3d_viewer.py +++ b/N2G/plugins/viewers/v3d_viewer/v3d_viewer.py @@ -48,21 +48,31 @@ ] } """ -from flask import Flask, render_template, Markup import os import json import logging +try: + from flask import Flask, render_template, Markup + + HAS_FLASK = True +except ImportError: + HAS_FLASK = False + log = logging.getLogger(__name__) app_dir = os.path.abspath(os.path.dirname(__file__)) -app = Flask( - __name__, static_folder=app_dir, static_url_path="", template_folder=app_dir -) +if HAS_FLASK: + app = Flask( + __name__, static_folder=app_dir, static_url_path="", template_folder=app_dir + ) + # based on https://stackoverflow.com/a/19269087/12300761 answer + app.jinja_env.filters["json"] = lambda v: Markup(json.dumps(v)) -# based on https://stackoverflow.com/a/19269087/12300761 answer -app.jinja_env.filters["json"] = lambda v: Markup(json.dumps(v)) + @app.route("/") + def home(): + return render_template("v3d_viewer.html", json_data=diagram_content) def run_v3d_viewer( @@ -97,8 +107,3 @@ def run_v3d_viewer( log.error("No diagram file or diagram data provided, stopping...") return app.run(host=ip, port=port, debug=debug, **kwargs) - - -@app.route("/") -def home(): - return render_template("v3d_viewer.html", json_data=diagram_content) diff --git a/N2G/plugins/viewers/yed_viewer/yed_viewer.py b/N2G/plugins/viewers/yed_viewer/yed_viewer.py index 1344cad..1b326d8 100644 --- a/N2G/plugins/viewers/yed_viewer/yed_viewer.py +++ b/N2G/plugins/viewers/yed_viewer/yed_viewer.py @@ -29,18 +29,34 @@ Diagrams directory should contain SVG files produced by yED Graph Editor application using ``File -> Export -> Save as type: SVG format`` feature. """ -from flask import Flask, render_template import os import json import logging +try: + from flask import Flask, render_template + + HAS_FLASK = True +except ImportError: + HAS_FLASK = False + log = logging.getLogger(__name__) app_dir = os.path.abspath(os.path.dirname(__file__)) -app = Flask( - __name__, static_folder=app_dir, static_url_path="", template_folder=app_dir -) +if HAS_FLASK: + app = Flask( + __name__, static_folder=app_dir, static_url_path="", template_folder=app_dir + ) + + @app.route("/") + def home(): + return render_template("yed_viewer.html", select2_menu_data=scan_graphs()) + + @app.route("/diagrams/") + def get_diagram(diagram_name): + with open(os.path.join(diagrams_directory, diagram_name)) as f: + return f.read() def scan_graphs() -> str: @@ -81,16 +97,5 @@ def run_yed_viewer( app.run(host=ip, port=port, debug=debug, **kwargs) -@app.route("/") -def home(): - return render_template("yed_viewer.html", select2_menu_data=scan_graphs()) - - -@app.route("/diagrams/") -def get_diagram(diagram_name): - with open(os.path.join(diagrams_directory, diagram_name)) as f: - return f.read() - - if __name__ == "__main__": run_yed_viewer() diff --git a/poetry.lock b/poetry.lock index c2bb873..7ab7859 100644 --- a/poetry.lock +++ b/poetry.lock @@ -132,11 +132,11 @@ python-versions = ">=3.6.1" [[package]] name = "charset-normalizer" -version = "2.0.12" +version = "2.1.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." category = "main" optional = true -python-versions = ">=3.5.0" +python-versions = ">=3.6.0" [package.extras] unicode_backport = ["unicodedata2"] @@ -269,7 +269,7 @@ typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.8\"" [[package]] name = "griffe" -version = "0.21.0" +version = "0.22.0" description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." category = "main" optional = true @@ -319,7 +319,7 @@ test-musl = ["networkx (>=2.5)", "pytest (>=7.0.1)"] [[package]] name = "imagesize" -version = "1.3.0" +version = "1.4.1" description = "Getting image size from png/jpeg/jpeg2000/gif file" category = "main" optional = true @@ -827,7 +827,7 @@ python-versions = ">=3.6" [[package]] name = "requests" -version = "2.28.0" +version = "2.28.1" description = "Python HTTP for Humans." category = "main" optional = true @@ -835,13 +835,13 @@ python-versions = ">=3.7, <4" [package.dependencies] certifi = ">=2017.4.17" -charset-normalizer = ">=2.0.0,<2.1.0" +charset-normalizer = ">=2,<3" idna = ">=2.5,<4" urllib3 = ">=1.21.1,<1.27" [package.extras] socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] +use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "six" @@ -1054,7 +1054,7 @@ optional = true python-versions = ">=2.7,<4.0" [package.extras] -full = ["cerberus (>=1.3.0,<1.4.0)", "jinja2 (>=3.0.0,<3.1.0)", "pyyaml (==6.0)", "deepdiff (>=5.8.0,<5.9.0)", "openpyxl (>=3.0.0,<3.1.0)", "tabulate (>=0.8.0,<0.9.0)", "ttp_templates (<1.0.0)", "yangson (>=1.4.0,<1.5.0)", "n2g (>=0.2.0,<0.3.0)"] +full = ["cerberus (>=1.3.0,<1.4.0)", "jinja2 (>=3.0.0,<3.1.0)", "pyyaml (==6.0)", "deepdiff (>=5.8.0,<5.9.0)", "openpyxl (>=3.0.0,<3.1.0)", "tabulate (>=0.8.0,<0.9.0)", "ttp_templates (<1.0.0)", "yangson (>=1.4.0,<1.5.0)", "N2G (>=0.2.0,<0.3.0)"] docs = ["readthedocs-sphinx-search (==0.1.1)", "Sphinx (==4.3.0)", "sphinx_rtd_theme (==1.0.0)", "sphinxcontrib-applehelp (==1.0.1)", "sphinxcontrib-devhelp (==1.0.1)", "sphinxcontrib-htmlhelp (==2.0.0)", "sphinxcontrib-jsmath (==1.0.1)", "sphinxcontrib-napoleon (==0.7)", "sphinxcontrib-qthelp (==1.0.2)", "sphinxcontrib-serializinghtml (==1.1.5)", "sphinxcontrib-spelling (==7.2.1)"] [[package]] @@ -1082,7 +1082,7 @@ python-versions = ">=3.6" [[package]] name = "typing-extensions" -version = "4.2.0" +version = "4.3.0" description = "Backported and Experimental Type Hints for Python 3.7+" category = "main" optional = false @@ -1103,7 +1103,7 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "virtualenv" -version = "20.15.0" +version = "20.15.1" description = "Virtual Python Environment builder" category = "dev" optional = false @@ -1246,8 +1246,8 @@ cfgv = [ {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, ] charset-normalizer = [ - {file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"}, - {file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"}, + {file = "charset-normalizer-2.1.0.tar.gz", hash = "sha256:575e708016ff3a5e3681541cb9d79312c416835686d054a23accb873b254f413"}, + {file = "charset_normalizer-2.1.0-py3-none-any.whl", hash = "sha256:5189b6f22b01957427f35b6a08d9a0bc45b46d3788ef5a92e978433c7a35f8a5"}, ] click = [ {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, @@ -1294,8 +1294,8 @@ gitpython = [ {file = "GitPython-3.1.27.tar.gz", hash = "sha256:1c885ce809e8ba2d88a29befeb385fcea06338d3640712b59ca623c220bb5704"}, ] griffe = [ - {file = "griffe-0.21.0-py3-none-any.whl", hash = "sha256:e9fb5eeb7c721e1d84804452bdc742bd57b120b13aba663157668ae2d217088a"}, - {file = "griffe-0.21.0.tar.gz", hash = "sha256:61ab3bc02b09afeb489f1aef44c646a09f1837d9cdf15943ac6021903a4d3984"}, + {file = "griffe-0.22.0-py3-none-any.whl", hash = "sha256:65c94cba634d6ad397c495b04ed5fd3f06d9b16c4f9f78bd63be9ea34d6b7113"}, + {file = "griffe-0.22.0.tar.gz", hash = "sha256:a3c25a2b7bf729ecee7cd455b4eff548f01c620b8f58a8097a800caad221f12e"}, ] identify = [ {file = "identify-2.5.1-py2.py3-none-any.whl", hash = "sha256:0dca2ea3e4381c435ef9c33ba100a78a9b40c0bab11189c7cf121f75815efeaa"}, @@ -1372,8 +1372,8 @@ igraph = [ {file = "igraph-0.9.11.tar.gz", hash = "sha256:52eeaf5c015e297d979fefc53038fbaaf5fff4fb5f5022dce43f3ddc78210515"}, ] imagesize = [ - {file = "imagesize-1.3.0-py2.py3-none-any.whl", hash = "sha256:1db2f82529e53c3e929e8926a1fa9235aa82d0bd0c580359c67ec31b2fddaa8c"}, - {file = "imagesize-1.3.0.tar.gz", hash = "sha256:cd1750d452385ca327479d45b64d9c7729ecf0b3969a58148298c77092261f9d"}, + {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"}, + {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, ] importlib-metadata = [ {file = "importlib_metadata-4.2.0-py3-none-any.whl", hash = "sha256:057e92c15bc8d9e8109738a48db0ccb31b4d9d5cfbee5a8670879a30be66304b"}, @@ -1653,8 +1653,8 @@ readthedocs-sphinx-search = [ {file = "readthedocs_sphinx_search-0.1.1-py3-none-any.whl", hash = "sha256:7216c260244e2272e5577e7c37771f7fd34eeeda229bbeb5735b79e04c54a047"}, ] requests = [ - {file = "requests-2.28.0-py3-none-any.whl", hash = "sha256:bc7861137fbce630f17b03d3ad02ad0bf978c844f3536d0edda6499dafce2b6f"}, - {file = "requests-2.28.0.tar.gz", hash = "sha256:d568723a7ebd25875d8d1eaf5dfa068cd2fc8194b2e483d7b1f7c81918dbec6b"}, + {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"}, + {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"}, ] six = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, @@ -1759,16 +1759,16 @@ typed-ast = [ {file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"}, ] typing-extensions = [ - {file = "typing_extensions-4.2.0-py3-none-any.whl", hash = "sha256:6657594ee297170d19f67d55c05852a874e7eb634f4f753dbd667855e07c1708"}, - {file = "typing_extensions-4.2.0.tar.gz", hash = "sha256:f1c24655a0da0d1b67f07e17a5e6b2a105894e6824b92096378bb3668ef02376"}, + {file = "typing_extensions-4.3.0-py3-none-any.whl", hash = "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02"}, + {file = "typing_extensions-4.3.0.tar.gz", hash = "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6"}, ] urllib3 = [ {file = "urllib3-1.26.9-py2.py3-none-any.whl", hash = "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14"}, {file = "urllib3-1.26.9.tar.gz", hash = "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"}, ] virtualenv = [ - {file = "virtualenv-20.15.0-py2.py3-none-any.whl", hash = "sha256:804cce4de5b8a322f099897e308eecc8f6e2951f1a8e7e2b3598dff865f01336"}, - {file = "virtualenv-20.15.0.tar.gz", hash = "sha256:4c44b1d77ca81f8368e2d7414f9b20c428ad16b343ac6d226206c5b84e2b4fcc"}, + {file = "virtualenv-20.15.1-py2.py3-none-any.whl", hash = "sha256:b30aefac647e86af6d82bfc944c556f8f1a9c90427b2fb4e3bfbf338cb82becf"}, + {file = "virtualenv-20.15.1.tar.gz", hash = "sha256:288171134a2ff3bfb1a2f54f119e77cd1b81c29fc1265a2356f3e8d14c7d58c4"}, ] watchdog = [ {file = "watchdog-2.1.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a735a990a1095f75ca4f36ea2ef2752c99e6ee997c46b0de507ba40a09bf7330"}, diff --git a/pyproject.toml b/pyproject.toml index bc35306..7cf2092 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] -name = "n2g" -version = "0.3.0" +name = "N2G" +version = "0.3.1" description = "Need To Graph" authors = ["Denis Mulyalin "] maintainers = ["Denis Mulyalin "] diff --git a/tests/Data/SAMPLE_CISCO_IOSXR_IP/cisco_xr/iosxr1.txt b/tests/Data/SAMPLE_CISCO_IOSXR_IP/cisco_xr/iosxr1.txt new file mode 100644 index 0000000..32f8440 --- /dev/null +++ b/tests/Data/SAMPLE_CISCO_IOSXR_IP/cisco_xr/iosxr1.txt @@ -0,0 +1,169 @@ +Sun Jul 3 06:30:39.479 UTC +interface Bundle-Ether10 + l2transport + ! +! +interface Loopback0 + ipv4 address 2.2.2.2/32 + ipv6 address fc00::1/128 +! +interface Loopback1 + description WHATEVER + ipv4 address 2.2.2.20/24 +! +interface Loopback2 + description loopback2 + ipv4 address 2.2.2.2/24 +! +interface Loopback13 + ipv4 address 1.1.1.10/24 +! +interface Loopback19 + description David + ipv4 address 20.20.20.20/24 +! +interface Loopback21 + ipv6 address 2345:425:2ca1::567:5673:23b5/128 +! +interface Loopback99 +! +interface Loopback100 + description ##locator## + ipv6 address fc00:1000:10::4/128 + ipv6 address fc00:1011:20::4/128 + ipv6 address fc00:1081:90::9/122 +! +interface Loopback101 + ipv4 address 192.0.2.18/24 + ipv4 address 203.0.113.4/24 secondary + ipv6 address 2001:db8:f00d::1/64 +! +interface Loopback111 + description Configured by NETCONF + ipv4 address 9.9.8.8/32 +! +interface Loopback123 + description "123 pyats 123" +! +interface Loopback200 + description ***MERGE LOOPBACK 200**** + ipv4 address 1.1.1.200/32 +! +interface Loopback555 + ipv4 address 2.2.2.2/24 +! +interface Loopback556 + ipv4 address 3.3.3.3/24 +! +interface Loopback666 + description "Link to Chamuco +! +interface Loopback701 + ipv4 address 10.0.1.1/24 +! +interface Loopback702 + ipv4 address 10.0.2.1/24 +! +interface Loopback703 + ipv4 address 192.168.0.1/24 +! +interface Loopback777 + description "Link to Chamuco" +! +interface Loopback1000 + ipv6 address e:0:0:66:44::/64 + ipv6 enable +! +interface Loopback1001 + ipv4 address 192.168.0.1/32 +! +interface Loopback1002 + ipv4 address 192.168.0.2/32 +! +interface Loopback1003 + ipv4 address 192.168.51.1/24 + shutdown +! +interface Loopback6500 + ipv4 address 198.51.100.0/32 +! +interface Loopback20222 +! +interface tunnel-ip99 + ipv4 mtu 1476 + ipv4 address 1.1.1.1/31 + tunnel mode gre ipv4 + tunnel source 99.99.99.1 + tunnel destination 2.2.2.2 +! +interface MgmtEth0/RP0/CPU0/0 + ipv4 address 10.10.20.175/24 +! +interface GigabitEthernet0/0/0/0.100 + description test1 + ipv4 address 10.1.1.1/29 + encapsulation dot1q 100 +! +interface GigabitEthernet0/0/0/0.200 + ipv4 address 10.1.1.1/29 +! +interface GigabitEthernet0/0/0/1 + ipv4 address 20.20.20.50/24 +! +interface GigabitEthernet0/0/0/1.200 + description test2 + ipv4 address 10.1.1.1/29 +! +interface GigabitEthernet0/0/0/2 + description Hola esto es una prueba + shutdown +! +interface GigabitEthernet0/0/0/3 + bundle id 20 mode active + shutdown +! +interface GigabitEthernet0/0/0/4 + shutdown +! +interface GigabitEthernet0/0/0/5 + shutdown +! +interface GigabitEthernet0/0/0/6 + shutdown +! +interface BVI511 + description BVI 511 + service-policy type pbr input POLICY-VL3929-INBOUND + ipv4 address 10.200.188.33/24 +! +interface preconfigure GigabitEthernet0/9/0/14 + bundle id 140 mode active + load-interval 30 +! +interface preconfigure GigabitEthernet0/9/0/15 + shutdown +! +interface preconfigure GigabitEthernet0/9/0/16 + shutdown +! +interface preconfigure GigabitEthernet0/9/0/17 + shutdown +! +interface preconfigure GigabitEthernet0/9/0/18 + shutdown +! +interface preconfigure GigabitEthernet0/9/0/19 + shutdown +! +interface preconfigure GigabitEthernet0/9/0/19.1300 + description MPLS:911042372:VPN-BREB + bandwidth 50000 + ipv4 mtu 1500 + ipv4 address 100.64.98.154/31 + proxy-arp + encapsulation dot1q 1371 +! + +RP/0/RP0/CPU0:ansible-iosxr# +Sun Jul 3 06:30:40.380 UTC +RP/0/RP0/CPU0:ansible-iosxr# \ No newline at end of file diff --git a/tests/Output/should_be_test_ip_drawing_yed_data_dict_cisco_xr.graphml b/tests/Output/should_be_test_ip_drawing_yed_data_dict_cisco_xr.graphml new file mode 100644 index 0000000..f7aefd3 --- /dev/null +++ b/tests/Output/should_be_test_ip_drawing_yed_data_dict_cisco_xr.graphml @@ -0,0 +1,526 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ansible-iosxrDevice + + {"id": "ansible-iosxr"} + + + + + + + 2.2.2.2/32Lo0global + + {"id": "2.2.2.2/32"} + + + + + + + 2.2.2.0/24Subnet + + {"id": "2.2.2.0/24"} + + + + + + + 1.1.1.0/24Subnet + + {"id": "1.1.1.0/24"} + + + + + + + 20.20.20.0/24Subnet + + {"id": "20.20.20.0/24"} + + + + + + + 192.0.2.0/24Subnet + + {"id": "192.0.2.0/24"} + + + + + + + 9.9.8.8/32Lo111global + + {"id": "9.9.8.8/32"} + + + + + + + 1.1.1.200/32Lo200global + + {"id": "1.1.1.200/32"} + + + + + + + 3.3.3.0/24Subnet + + {"id": "3.3.3.0/24"} + + + + + + + 10.0.1.0/24Subnet + + {"id": "10.0.1.0/24"} + + + + + + + 10.0.2.0/24Subnet + + {"id": "10.0.2.0/24"} + + + + + + + 192.168.0.0/24Subnet + + {"id": "192.168.0.0/24"} + + + + + + + 192.168.0.1/32Lo1001global + + {"id": "192.168.0.1/32"} + + + + + + + 192.168.0.2/32Lo1002global + + {"id": "192.168.0.2/32"} + + + + + + + 192.168.51.0/24Subnet + + {"id": "192.168.51.0/24"} + + + + + + + 198.51.100.0/32Lo6500global + + {"id": "198.51.100.0/32"} + + + + + + + 1.1.1.0/31Subnet + + {"id": "1.1.1.0/31"} + + + + + + + 10.10.20.0/24Subnet + + {"id": "10.10.20.0/24"} + + + + + + + 10.1.1.0/29Subnet + + {"id": "10.1.1.0/29"} + + + + + + + 10.200.188.0/24Subnet + + {"id": "10.200.188.0/24"} + + + + + + + + { + "ansible-iosxr:Lo0": { + "ip": "2.2.2.2", + "netmask": "32", + "network": "2.2.2.2/32" + } +}{"sid": "2.2.2.2/32", "tid": "ansible-iosxr", "id": "c81c9b85aa25a309aaff6b4fa8bbf4fb"} + + + + + + 2.2.2.20/24 + + + { + "ansible-iosxr:Lo1": { + "ip": "2.2.2.20", + "netmask": "24", + "network": "2.2.2.0/24", + "port_description": "WHATEVER" + } +}{"sid": "2.2.2.0/24", "tid": "ansible-iosxr", "id": "2f0d797518b1c1340db406d0f53b3c16"} + + + + + + 2.2.2.2/24 + + + { + "ansible-iosxr:Lo2": { + "ip": "2.2.2.2", + "netmask": "24", + "network": "2.2.2.0/24", + "port_description": "loopback2" + } +}{"sid": "2.2.2.0/24", "tid": "ansible-iosxr", "id": "50136b522d1ef8423bd0116ab6aaa720"} + + + + + + 1.1.1.10/24 + + + { + "ansible-iosxr:Lo13": { + "ip": "1.1.1.10", + "netmask": "24", + "network": "1.1.1.0/24" + } +}{"sid": "1.1.1.0/24", "tid": "ansible-iosxr", "id": "5f9550c0acb9875452d55341e8819b85"} + + + + + + 20.20.20.20/24 + + + { + "ansible-iosxr:Lo19": { + "ip": "20.20.20.20", + "netmask": "24", + "network": "20.20.20.0/24", + "port_description": "David" + } +}{"sid": "20.20.20.0/24", "tid": "ansible-iosxr", "id": "bbd8196c9e08639f0dd3f46ee3afa941"} + + + + + + 192.0.2.18/24 + + + { + "ansible-iosxr:Lo101": { + "ip": "192.0.2.18", + "netmask": "24", + "network": "192.0.2.0/24" + } +}{"sid": "192.0.2.0/24", "tid": "ansible-iosxr", "id": "6ba3e1d120cf7a34ecc7b8313a04331e"} + + + + + + + + { + "ansible-iosxr:Lo111": { + "ip": "9.9.8.8", + "netmask": "32", + "network": "9.9.8.8/32", + "port_description": "Configured by NETCONF" + } +}{"sid": "9.9.8.8/32", "tid": "ansible-iosxr", "id": "7b0a41f824799b89b731bf3ab832e447"} + + + + + + + + { + "ansible-iosxr:Lo200": { + "ip": "1.1.1.200", + "netmask": "32", + "network": "1.1.1.200/32", + "port_description": "***MERGE LOOPBACK 200****" + } +}{"sid": "1.1.1.200/32", "tid": "ansible-iosxr", "id": "cb69ee07a8c0ce5acad453864cc3f026"} + + + + + + 3.3.3.3/24 + + + { + "ansible-iosxr:Lo556": { + "ip": "3.3.3.3", + "netmask": "24", + "network": "3.3.3.0/24" + } +}{"sid": "3.3.3.0/24", "tid": "ansible-iosxr", "id": "18940f26a40d1304d1dfbf196753b264"} + + + + + + 10.0.1.1/24 + + + { + "ansible-iosxr:Lo701": { + "ip": "10.0.1.1", + "netmask": "24", + "network": "10.0.1.0/24" + } +}{"sid": "10.0.1.0/24", "tid": "ansible-iosxr", "id": "476ee2953c082ebc3aaf49f2442bb442"} + + + + + + 10.0.2.1/24 + + + { + "ansible-iosxr:Lo702": { + "ip": "10.0.2.1", + "netmask": "24", + "network": "10.0.2.0/24" + } +}{"sid": "10.0.2.0/24", "tid": "ansible-iosxr", "id": "2f2d387680a5d5e978e480fd886bd168"} + + + + + + 192.168.0.1/24 + + + { + "ansible-iosxr:Lo703": { + "ip": "192.168.0.1", + "netmask": "24", + "network": "192.168.0.0/24" + } +}{"sid": "192.168.0.0/24", "tid": "ansible-iosxr", "id": "9baff6767d0d2a8cc71387bd9f379e4c"} + + + + + + + + { + "ansible-iosxr:Lo1001": { + "ip": "192.168.0.1", + "netmask": "32", + "network": "192.168.0.1/32" + } +}{"sid": "192.168.0.1/32", "tid": "ansible-iosxr", "id": "78b490d38a8841e5152b8d9320a99ba9"} + + + + + + + + { + "ansible-iosxr:Lo1002": { + "ip": "192.168.0.2", + "netmask": "32", + "network": "192.168.0.2/32" + } +}{"sid": "192.168.0.2/32", "tid": "ansible-iosxr", "id": "c8534f138e9333df0783d826791c4df2"} + + + + + + 192.168.51.1/24 + + + { + "ansible-iosxr:Lo1003": { + "ip": "192.168.51.1", + "netmask": "24", + "network": "192.168.51.0/24" + } +}{"sid": "192.168.51.0/24", "tid": "ansible-iosxr", "id": "71870213581a42a4c45e51bbb7f123e3"} + + + + + + + + { + "ansible-iosxr:Lo6500": { + "ip": "198.51.100.0", + "netmask": "32", + "network": "198.51.100.0/32" + } +}{"sid": "198.51.100.0/32", "tid": "ansible-iosxr", "id": "4d7b59d0bc93d3bc04c569900544d41a"} + + + + + + 1.1.1.1/31 + + + { + "ansible-iosxr:tunnel-ip99": { + "ip": "1.1.1.1", + "netmask": "31", + "network": "1.1.1.0/31" + } +}{"sid": "1.1.1.0/31", "tid": "ansible-iosxr", "id": "b6167aeb6bf401dc129c7467fea77ac8"} + + + + + + 10.10.20.175/24 + + + { + "ansible-iosxr:MGMT0/RP0/CPU0/0": { + "ip": "10.10.20.175", + "netmask": "24", + "network": "10.10.20.0/24" + } +}{"sid": "10.10.20.0/24", "tid": "ansible-iosxr", "id": "8e22d9dcf2550099d1025a0f9253eb1c"} + + + + + + 10.1.1.1/29 + + + { + "ansible-iosxr:GE0/0/0/0.100": { + "ip": "10.1.1.1", + "netmask": "29", + "network": "10.1.1.0/29", + "port_description": "test1" + } +}{"sid": "10.1.1.0/29", "tid": "ansible-iosxr", "id": "6e20c3bc302ee46b360f777ff0dd9d66"} + + + + + + 20.20.20.50/24 + + + { + "ansible-iosxr:GE0/0/0/1": { + "ip": "20.20.20.50", + "netmask": "24", + "network": "20.20.20.0/24" + } +}{"sid": "20.20.20.0/24", "tid": "ansible-iosxr", "id": "879c7469196a94204208dd36ad6d4a9a"} + + + + + + 10.200.188.33/24 + + + { + "ansible-iosxr:BVI511": { + "ip": "10.200.188.33", + "netmask": "24", + "network": "10.200.188.0/24", + "port_description": "BVI 511" + } +}{"sid": "10.200.188.0/24", "tid": "ansible-iosxr", "id": "4c2022c6a0bbb49080aa00ee4e1b6f6c"} + + + + + \ No newline at end of file diff --git a/tests/test_cli_ip_data_plugin.py b/tests/test_cli_ip_data_plugin.py index 6978c37..46e0c3c 100644 --- a/tests/test_cli_ip_data_plugin.py +++ b/tests/test_cli_ip_data_plugin.py @@ -717,23 +717,23 @@ def test_ip_drawing_yed_data_dict_fortigate(): set ip 10.1.0.1 255.255.255.252 set description "bgp to upstream FW" next - + forti-fw-01 (Corporate) # get system arp Address Age(min) Hardware Addr Interface 1.1.1.10 0 22:31:5e:00:34:d1 vms_vlan 10.0.0.10 0 22:31:5e:00:34:c2 NMS_mgmt 10.0.0.31 0 22:31:5e:00:34:31 NMS_mgmt - """, - """ + """, + """ forti-fw-02 (Corporate) # get system config config system interface edit "fw_1" set vdom "root" set ip 10.1.0.2 255.255.255.252 set description "bgp to forti-fw-01" - next - """] - } + next + """] + } config = { "add_arp": True } @@ -746,4 +746,20 @@ def test_ip_drawing_yed_data_dict_fortigate(): assert normalize_xml(produced.read()) == normalize_xml(should_be.read()) # test_ip_drawing_yed_data_dict_fortigate() - \ No newline at end of file + + +def test_ip_drawing_yed_data_dict_cisco_xr(): + with open("./Data/SAMPLE_CISCO_IOSXR_IP/cisco_xr/iosxr1.txt") as f: + data = {"cisco_xr": [f.read()]} + config = { + "add_arp": True + } + drawing = create_yed_diagram() + drawer = cli_ip_data(drawing, **config) + drawer.work(data) + drawer.drawing.dump_file(filename="test_ip_drawing_yed_data_dict_cisco_xr.graphml", folder="./Output/") + with open ("./Output/test_ip_drawing_yed_data_dict_cisco_xr.graphml") as produced: + with open("./Output/should_be_test_ip_drawing_yed_data_dict_cisco_xr.graphml") as should_be: + assert normalize_xml(produced.read()) == normalize_xml(should_be.read()) + +# test_ip_drawing_yed_data_dict_cisco_xr() \ No newline at end of file