From 08dd2c0aed8fac833779d74b0a8e80bcb6e7d491 Mon Sep 17 00:00:00 2001 From: Sunami Dasgupta Date: Sun, 20 Oct 2024 21:53:03 -0700 Subject: [PATCH] Diagram class related to #127 --- autogole-api/packaging/Dockerfile | 8 +- autogole-api/packaging/icons/host.png | Bin 0 -> 15239 bytes autogole-api/packaging/icons/switch.png | Bin 0 -> 2532 bytes autogole-api/requirements.txt | 1 + autogole-api/src/python/RTMon/worker.py | 6 + .../src/python/RTMonLibs/DiagramWorker.py | 146 ++++++++++++++++++ autogole-api/src/python/RTMonLibs/Template.py | 8 + 7 files changed, 166 insertions(+), 3 deletions(-) create mode 100644 autogole-api/packaging/icons/host.png create mode 100644 autogole-api/packaging/icons/switch.png create mode 100644 autogole-api/src/python/RTMonLibs/DiagramWorker.py diff --git a/autogole-api/packaging/Dockerfile b/autogole-api/packaging/Dockerfile index 7997dc1..bf2534b 100644 --- a/autogole-api/packaging/Dockerfile +++ b/autogole-api/packaging/Dockerfile @@ -1,11 +1,12 @@ FROM opensciencegrid/software-base:23-al8-release RUN yum -y install wget epel-release && \ - yum -y install git python3 python3-pyyaml python3-devel python3-pip gcc openssl-devel cronie python3-pyOpenSSL fetch-crl && \ + yum -y install git python3 python3-pyyaml python3-devel python3-pip gcc openssl-devel cronie python3-pyOpenSSL fetch-crl graphviz && \ yum clean all RUN mkdir -p /opt/ && \ mkdir -p /srv/ && \ + mkdir -p /srv/icons/ && \ mkdir -p /etc/rtmon/templates/ && \ mkdir -p /var/log/rtmon/ && \ mkdir -p /etc/grid-security/certificates/ @@ -20,12 +21,13 @@ RUN git clone https://github.com/sdn-sense/sense-o-py-client.git /opt/sense-o-py # Install RTMON (TODO, replace to ESnet repo once merged) RUN git clone https://github.com/esnet/sense-rtmon.git /opt/sense-rtmon && \ - cd /opt/sense-rtmon/autogole-api/ && pip3 install -r requirements.txt && pip3 install . && \ + cd /opt/sense-rtmon/autogole-api/ && pip3 install -r requirements.txt && pip3 install diagrams && pip3 install . && \ cp src/templates/* /etc/rtmon/templates/ RUN wget https://raw.githubusercontent.com/sdn-sense/rm-configs/master/CAs/SiteRM.pem -O /etc/grid-security/certificates/e52ac827.0 ADD files/etc/supervisord.d/10-server.conf /etc/supervisord.d/10-server.conf - +COPY icons/host.png /srv/icons/host.png +COPY icons/switch.png /srv/icons/switch.png # Get latest CA's RUN fetch-crl || echo "Supress warnings." diff --git a/autogole-api/packaging/icons/host.png b/autogole-api/packaging/icons/host.png new file mode 100644 index 0000000000000000000000000000000000000000..71fcd4a81d70a01235d09042649cf9b069aed1e2 GIT binary patch literal 15239 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%0Ad!ey(vJaye5M;>90SJ-pk{@iQkL73qP}B z%l8lD`?tAC#18KFi#b>tTS(imOLX|6g6jNrOL{u&0@KF~dnlC$sBm#Qa)j$QUGFws zLGR_kjM2j!K6|8tA+^f+DDEl*9IvY#3b5mcb66T%9!kN1Jspn~uAuiX@Vy(B#uj!Q zKJW0E!$GjJrk?k==CXR;v$(s7HQJPO+~KBX2NEMgnKLo6Gd(gS5Us}D;oRR9JT)3d z^f!rY8GBE&=X9~8&$x(SyFu{QZ5!`z&6PZSmFxm%E>}3*%bSxBg-;JH*Q+fK{|*&i z5#{fp)sP%LM3S@=Qewlnsi@{+xmjeJn;1o)pX)(NKYw3-|4gLFR#aBS)yisz`HgxnR?eP; z$324WJaV4w{0m){<#Z5C-+heyi>3DzsN;>)cuAkH4;6^g-kw@kzcN{J?Ql2x`TO$W zyd+UP0PxkJvywhbQsOb{#c@ae#ZuCDA9GrsQvqx?fe*IrqvS@7$Ud~6Nx}p67hK}> zrE-z2kI|R(MbGhKTsWQ@jh&CDM#D>EB3PgHoSjf7ipw}qaK+B217UsrMd^|oHGHsb zA2yrw9Tk_N!G`8mR%Gnq(*-G==lc84Ngr4U0<7A8fb|Pf2{7DwGv1zB7EXJbSCXPR zd$oe{n-<(q)7z+LM1PZApNF;q`S05gbjk1Vf3J}mI~0JLhGte|>~Sd)1c{ZP6ifym zlA=PXtgdJ8nM+R3@Pm69_-Ni_dig%s0cT}RJ%8SuW7qobg_~N<#E}CD(Cf(kvDl^S zHXSR$`x4+mVD$0g?HS{V4h_05zx<13tl4pZn{`cc(CQRG_B}y!T_f*&v6~6QLwI>? z1cQV8yUbryR>fC`&UV@7A0`yLBD4SOW%i%FOn;LfUDfFKbeeur|j~MiwI^;LX=%dD;0J>EXXg1>FDqmgS%-%DX<)kS8J;BB4S(N;*>tMza%FMOAwdvnf{hIFy zLfa|NqV!CTUbyD6&xztPUjHnUpQ~zRWYz{nrokp_D}VVimu&~7cXc|DoqvJl|N35$ zo8q8gFl4g{{4*z?aD(EZi u`|E`OrGlXPMyqN4IPa6U$ literal 0 HcmV?d00001 diff --git a/autogole-api/requirements.txt b/autogole-api/requirements.txt index 31f34b8..a6ec8ad 100644 --- a/autogole-api/requirements.txt +++ b/autogole-api/requirements.txt @@ -2,3 +2,4 @@ psutil requests pyyaml grafana-client +diagrams diff --git a/autogole-api/src/python/RTMon/worker.py b/autogole-api/src/python/RTMon/worker.py index e796121..dd27bc3 100644 --- a/autogole-api/src/python/RTMon/worker.py +++ b/autogole-api/src/python/RTMon/worker.py @@ -84,8 +84,14 @@ def submit_exe(self, filename, fout): self._updateState(filename, fout) def delete_exe(self, filename, fout): + """Delete Action Execution""" self.logger.info('Delete Execution: %s, %s', filename, fout) + #Deleting the diagram image + diagram_filename = f"{self.config.get('image_dir', '/srv/images')}/diagram_{fout['referenceUUID']}.png" + if os.path.exists(diagram_filename): + os.remove(diagram_filename) + self.logger.info(f"Removed diagram image {diagram_filename}") # Delete the dashboard and template from Grafana for grafDir, dirVals in self.dashboards.items(): for dashbName, dashbVals in dirVals.items(): diff --git a/autogole-api/src/python/RTMonLibs/DiagramWorker.py b/autogole-api/src/python/RTMonLibs/DiagramWorker.py new file mode 100644 index 0000000..2ad27c2 --- /dev/null +++ b/autogole-api/src/python/RTMonLibs/DiagramWorker.py @@ -0,0 +1,146 @@ + +import os +from diagrams import Diagram, Cluster, Edge +from diagrams.custom import Custom + +def _processName(name): + """Process Name for Diagram and replace all special chars with _""" + for repl in [[" ", "_"], [":", "_"], ["/", "_"], ["-", "_"], [".", "_"], ["?", "_"]]: + name = name.replace(repl[0], repl[1]) + return name + +class DiagramWorker: + HOST_ICON_PATH = '/srv/icons/host.png' + SWITCH_ICON_PATH = '/srv/icons/switch.png' + + def __init__(self, indata): + self.indata = indata + self.objects = {} + self.added = {} + self.linksadded = set() + self.popreverse = None + + def _d_findItem(self, fval, fkey): + """Find Item where fkey == fval""" + for key, vals in self.objects.items(): + if vals.get('data', {}).get(fkey, '') == fval: + return key, vals + return None, None + + @staticmethod + def d_LinkLabel(vals1, vals2): + """Get Link Label""" + label = "" + if vals1.get('data', {}).get('Type', '') == "Host": + label = f"Port1: {vals1['data']['Interface']}" + elif vals1.get('data', {}).get('Type', '') == "Switch": + label = f"Port1: {vals1['data']['Name']}" + # Get second side info: + if vals2.get('data', {}).get('Type', '') == "Host": + label += f"\nPort2: {vals2['data']['Interface']}" + elif vals2.get('data', {}).get('Type', '') == "Switch": + label += f"\nPort2: {vals2['data']['Name']}" + if vals1.get('data', {}).get('Vlan', None): + label += f"\nVlan: {vals1['data']['Vlan']}" + elif vals2.get('data', {}).get('Vlan', None): + label += f"\nVlan: {vals2['data']['Vlan']}" + return label + + def d_addLink(self, val1, val2, key, fkey): + """Add Link between 2 objects""" + if val1 and val2 and key and fkey: + if key == fkey: + return + + link_keys = tuple(sorted([key, fkey])) + if link_keys in self.linksadded: + return + self.linksadded.add(link_keys) + + val1["obj"] >> Edge(label=self.d_LinkLabel(val1, val2)) << val2["obj"] + + def d_addLinks(self): + """Identify Links between items""" + for key, vals in self.objects.items(): + data_type = vals.get('data', {}).get('Type', '') + if data_type == "Host": + fKey, fItem = self._d_findItem(key, 'PeerHost') + if fKey and fItem: + self.d_addLink(self.objects[key], fItem, key, fKey) + elif data_type == "Switch": + if 'Peer' in vals.get('data', {}) and vals['data']['Peer'] != "?peer?": + fKey, fItem = self._d_findItem(vals['data']['Peer'], "Port") + if fKey and fItem: + self.d_addLink(self.objects[key], fItem, key, fKey) + elif 'PeerHost' in vals.get('data', {}): + fKey = vals['data']['PeerHost'] + fItem = self.objects.get(fKey) + if fItem: + self.d_addLink(self.objects[key], fItem, key, fKey) + + def d_addHost(self, item): + name = f"Host: {item['Name'].split(':')[1]}" + name += f"\nInterface: {item['Interface']}" + name += f"\nVlan: {item['Vlan']}" + if 'IPv4' in item and item['IPv4'] != "?ipv4?": + name += f"\nIPv4: {item['IPv4']}" + if 'IPv6' in item and item['IPv6'] != "?ipv6?": + name += f"\nIPv6: {item['IPv6']}" + + worker = Custom(name, self.HOST_ICON_PATH) + self.objects[item['Name']] = {"obj": worker, "data": item} + return worker + + def d_addSwitch(self, item): + if item['Node'] in self.added: + self.objects[item['Port']] = {"obj": self.objects[self.added[item['Node']]]["obj"], "data": item} + return + switch1 = Custom(item['Node'].split(":")[1], self.SWITCH_ICON_PATH) + if 'Peer' in item and item['Peer'] != "?peer?": + self.added[item['Node']] = item['Port'] + self.objects[item['Port']] = {"obj": switch1, "data": item} + elif 'PeerHost' in item: + uniqname = _processName(f'{item["Node"]}_{item["Name"]}') + self.added[item['Node']] = uniqname + self.objects[uniqname] = {"obj": switch1, "data": item} + return switch1 + + def addItem(self, item): + site = self.identifySite(item) + if item['Type'] == 'Host': + with Cluster(site): + return self.d_addHost(item) + elif item['Type'] == 'Switch': + with Cluster(site): + return self.d_addSwitch(item) + + def identifySite(self, item): + site = None + if item['Type'] == 'Host': + site = item['Name'].split(':')[0] + elif item['Type'] == 'Switch': + site = item['Node'].split(':')[0] + return site + + def setreverse(self, item): + if item['Type'] == 'Host' and self.popreverse == None: + self.popreverse = False + elif item['Type'] == 'Host' and self.popreverse == False: + self.popreverse = True + elif item['Type'] == 'Host' and self.popreverse == True: + self.popreverse = False + + def createGraph(self, output_filename): + output_dir = os.path.dirname(output_filename) + if not os.path.exists(output_dir): + os.makedirs(output_dir) + + with Diagram("Network Topology", show=False, filename=output_filename): + while len(self.indata) > 0: + if self.popreverse == None or self.popreverse == False: + item = self.indata.pop(0) + elif self.popreverse == True: + item = self.indata.pop() + self.addItem(item) + self.setreverse(item) + self.d_addLinks() diff --git a/autogole-api/src/python/RTMonLibs/Template.py b/autogole-api/src/python/RTMonLibs/Template.py index 984db43..e940865 100644 --- a/autogole-api/src/python/RTMonLibs/Template.py +++ b/autogole-api/src/python/RTMonLibs/Template.py @@ -4,6 +4,7 @@ import copy import os.path from RTMonLibs.GeneralLibs import loadJson, dumpJson, dumpYaml, escape, getUUID +from RTMonLibs.DiagramWorker import DiagramWorker def _processName(name): """Process Name for Mermaid and replace all special chars with _""" @@ -628,6 +629,13 @@ def t_createTemplate(self, *args, **kwargs): # Add Mermaid (Send copy of args, as t_createMermaid will modify it by del items) orig_args = copy.deepcopy(args) self.generated['panels'] += self.t_createMermaid(*orig_args) + #Generate Diagrams + try: + diagram_filename = f"{self.config.get('image_dir', '/srv/images')}/diagram_{kwargs['referenceUUID']}" + DiagramWorker(self.orderlist).createGraph(diagram_filename) + self.logger.info(f"Diagram saved at {diagram_filename}.png") + except IOError as ex: + self.logger.error('Failed to create diagram: %s', ex) # Add Links on top of the page self.generated['links'] = self.t_addLinks(*args, **kwargs) # Add Debug Info (manifest, instance)