Created
September 29, 2023 11:41
-
-
Save itsecworks/5980ac38e818e2e4a5f343e29d6b95f3 to your computer and use it in GitHub Desktop.
graphviz palo alto config vizualisation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
# -*- coding: utf-8 -*- | |
# Author: Ist wurst... | |
import pdb | |
import sys | |
import xml.etree.ElementTree as ET | |
import json | |
from graphviz import Digraph | |
def get_values_pa(xml_output): | |
tree = ET.parse(xml_output) | |
root = tree.getroot() | |
dict = {} | |
dict["template"] = {} | |
for tmpl in root.findall("./devices/entry/template/entry"): | |
tmpl_name = tmpl.attrib["name"] | |
dict["template"][tmpl_name] = {} | |
dict["template"][tmpl_name]["vsys"] = {} | |
for vsys in tmpl.findall("./config/devices/entry/vsys/entry"): | |
vsys_name = vsys.attrib["name"] | |
dict["template"][tmpl_name]["vsys"][vsys_name] = {} | |
dict["template"][tmpl_name]["vsys"][vsys_name]["zone"] = {} | |
for zone in vsys.findall("./zone/entry"): | |
zone_name = zone.attrib["name"] | |
dict["template"][tmpl_name]["vsys"][vsys_name]["zone"][zone_name] = {} | |
dict["template-stack"] = {} | |
for tmplstk in root.findall("./devices/entry/template-stack/entry"): | |
tmplstk_name = tmplstk.attrib["name"] | |
dict["template-stack"][tmplstk_name] = {} | |
tmpl_list = [] | |
for tmpl in tmplstk.findall("./templates/member"): | |
tmpl_name = tmpl.text | |
tmpl_list.append(tmpl_name) | |
dict["template-stack"][tmplstk_name]["templates"] = tmpl_list | |
dvc_list = [] | |
for dvc in tmplstk.findall("./devices/entry"): | |
dvc_id = dvc.attrib["name"] | |
dvc_list.append(dvc_id) | |
dict["template-stack"][tmplstk_name]["devices"] = dvc_list | |
dict["device-group"] = {} | |
for dg in root.findall("./devices/entry/device-group/entry"): | |
dg_name = dg.attrib["name"] | |
dict["device-group"][dg_name] = {} | |
dvc_list = [] | |
for dvc in dg.findall("./devices/entry"): | |
dvc_id = dvc.attrib["name"] | |
vsyses = dvc.findall("./vsys/entry") | |
if not vsyses: | |
print("element vsys not found or element vsys has no subelement! dg: " + str(dg.attrib["name"])) | |
data = dvc_id | |
dvc_list.append(data) | |
if vsyses is None: | |
print("subelement exist, but element (vsysid) not found! dg: " + str(dg.attrib["name"])) | |
data = dvc_id | |
dvc_list.append(data) | |
else: | |
for vsys in dvc.findall("./vsys/entry"): | |
vsys_name = vsys.attrib["name"] | |
data = dvc_id + ' - ' + vsys_name | |
dvc_list.append(data) | |
dict["device-group"][dg_name]["devices"] = dvc_list | |
for dg in root.findall("./readonly/devices/entry/device-group/entry"): | |
dg_name = dg.attrib["name"] | |
for parent_dg in dg.findall("./parent-dg"): | |
if parent_dg is not None: | |
dg_p_name = parent_dg.text | |
else: | |
dg_p_name = "no parent" | |
dict["device-group"][dg_name]["parent"] = dg_p_name | |
json_obj = json.dumps(dict, indent=4) | |
print(json_obj) | |
return dict | |
def digraph_creator(dict): | |
g = Digraph( | |
name='config_topo_dg', | |
filename='config_topo_dg.gv', | |
graph_attr={'fontsize': '30', 'rankdir': 'DT', 'splines': 'true', 'overlap': 'scale', 'imagepath': 'C:/Users/akdaniel/Downloads/nw_topo/', 'label': 'Palo Alto Panorama Configuration Topology - device-groups'}, | |
strict=True | |
) | |
g.attr('node', shape='box') | |
for dg in dict['device-group']: | |
table = '<table border="1" cellborder="0" cellpadding="2" bgcolor="#33CBFF">\n' | |
table += ' <tr>\n <td color="#089FD3" bgcolor="#089FD3" align="center" border="5">\n <font color="white">device-group: {tmpl_name}</font>\n </td>\n </tr>\n'.format(tmpl_name=dg) | |
groupname = 'devices' | |
if groupname in dict['device-group'][dg]: | |
table += ' <tr>\n <td align="left" port="{group_id}">• assigned {group_name}</td>\n </tr>\n'.format(group_id=groupname, group_name=groupname) | |
for id, value in enumerate(dict['device-group'][dg]['devices']): | |
entry_id = groupname + str(id) | |
table += ' <tr>\n <td align="left" port="{entry_id}"> · {entry_name}</td>\n </tr>\n'.format(entry_id=entry_id, entry_name=value) | |
table += '</table>' | |
label = '<\n' + table + '\n>' | |
g.node(dg, penwidth='0', fontname='Arial', label=label) | |
if "parent" in dict['device-group'][dg]: | |
dgparent = dict['device-group'][dg]['parent'] | |
g.edge(dg, dgparent, dir='back', color='#089FD3') | |
g.view() | |
g = Digraph( | |
name='config_topo_tmpl', | |
filename='config_topo_tmpl.gv', | |
graph_attr={'fontsize': '30', 'rankdir': 'DT', 'splines': 'true', 'overlap': 'scale', 'imagepath': 'C:/Users/akdaniel/Downloads/nw_topo/', 'label': 'Palo Alto Panorama Configuration Topology - template-stacks'}, | |
strict=True | |
) | |
g.attr('node', shape='box') | |
for template in dict['template']: | |
table = '<table border="1" cellborder="0" cellpadding="2" bgcolor="#FFD580">\n' | |
table += ' <tr>\n <td color="orange" bgcolor="orange" align="center" border="5">\n <font color="white">Template: {tmpl_name}</font>\n </td>\n </tr>\n'.format(tmpl_name=template) | |
table += ' <tr>\n <td align="left" port="{group_id}"> • {group_name} configuration</td>\n </tr>\n'.format(group_id='vsys', group_name='vsys') | |
i = 0 | |
for vsys in dict['template'][template]['vsys']: | |
entry_id = 'vsys_' + str(i) | |
i += 1 | |
table += ' <tr>\n <td align="left" port="{entry_id}"> • {entry_name}</td>\n </tr>\n'.format(entry_id=entry_id, entry_name=vsys) | |
table += ' <tr>\n <td align="left" port="{group_id}"> • {group_name} configuration</td>\n </tr>\n'.format(group_id='zone', group_name='zone') | |
j = 0 | |
for zone in dict['template'][template]['vsys'][vsys]['zone']: | |
subentry_id = 'zone' + str(j) | |
j += 1 | |
table += ' <tr>\n <td align="left" port="{entry_id}"> · {entry_name}</td>\n </tr>\n'.format(entry_id=subentry_id, entry_name=zone) | |
table += '</table>' | |
label = '<\n' + table + '\n>' | |
g.node(template, penwidth='0', fontname='Arial', label=label) | |
for templatestack in dict['template-stack']: | |
table = '<table border="1" cellborder="0" cellpadding="2" bgcolor="#33CBFF">\n' | |
table += ' <tr>\n <td color="#089FD3" bgcolor="#089FD3" align="center" border="5">\n <font color="white">Template-stack: {tmplst_name}</font>\n </td>\n </tr>\n'.format(tmplst_name=templatestack) | |
groupname = 'devices' | |
if groupname in dict['template-stack'][templatestack]: | |
table += ' <tr>\n <td align="left" port="{group_id}">• assigned {group_name}</td>\n </tr>\n'.format(group_id=groupname, group_name=groupname) | |
for id, value in enumerate(dict['template-stack'][templatestack][groupname]): | |
entry_id = groupname + str(id) | |
table += ' <tr>\n <td align="left" port="{entry_id}"> · {entry_name}</td>\n </tr>\n'.format(entry_id=entry_id, entry_name=value) | |
groupname = 'templates' | |
if groupname in dict['template-stack'][templatestack]: | |
table += ' <tr>\n <td align="left" port="{group_id}">• assigned {group_name}</td>\n </tr>\n'.format(group_id=groupname, group_name=groupname) | |
for id, value in enumerate(dict['template-stack'][templatestack][groupname]): | |
entry_id = groupname + str(id) | |
table += ' <tr>\n <td align="left" port="{entry_id}"> · {entry_name}</td>\n </tr>\n'.format(entry_id=entry_id, entry_name=value) | |
table += '</table>' | |
label = '<\n' + table + '\n>' | |
g.node(templatestack, penwidth='0', fontname='Arial', label=label) | |
templatelist = dict['template-stack'][templatestack]['templates'] | |
g.edge(templatestack, templatelist[0], dir='back', color='#089FD3') | |
for i in (range(len(templatelist)-1)): | |
g.edge(templatelist[i], templatelist[i+1], dir='back', color='orange') | |
g.view() | |
print(g.source) | |
def main(argv): | |
filename = 'C:\\Users\\akdaniel\\Downloads\\running-config\\running-config.xml' | |
config_data = get_values_pa(filename) | |
#with open('C:\\Users\\akdaniel\\Downloads\\running-config\\panorama_config_topology_orig.json', 'w') as panorama_config: | |
# panorama_config.write(json.dumps(config_data)) | |
#with open('C:\\Users\\akdaniel\\Downloads\\running-config\\panorama_config_topology.json', 'r') as panorama_config: | |
# config_data = json.load(panorama_config) | |
digraph_creator(config_data) | |
if __name__ == "__main__": | |
main(sys.argv[1:]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment