Created
October 31, 2024 20:29
-
-
Save RezaAmbler/fcba2e949d7cab0775337d6fa73cc1f3 to your computer and use it in GitHub Desktop.
Generator PDF report of LLDP connections from LibreNMS
This file contains hidden or 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/python | |
| """ | |
| Network Topology Visualization Generator | |
| This script generates a PDF file representing the network topology using CDP (Cisco Discovery Protocol) | |
| and LLDP (Link Layer Discovery Protocol) data from LibreNMS. It visualizes network device connections | |
| using the Graphviz library to create a directed graph representation. | |
| Requirements: | |
| - requests: For API interactions | |
| - configparser: For potential future config file support | |
| - graphviz: For generating the network topology diagram | |
| The script queries the LibreNMS API to fetch device and link information, then creates a visual | |
| representation of how the devices are connected in the network. | |
| """ | |
| import requests | |
| import configparser | |
| import graphviz | |
| # API Configuration | |
| # ---------------- | |
| # Base URL for the LibreNMS API | |
| lnms_api = 'http://****/api/v0' | |
| # Authentication token for API access | |
| # TODO: Consider moving this to a secure configuration file | |
| lnms_token = '******' | |
| # Headers required for API authentication | |
| request_headers = { | |
| "X-Auth-Token": lnms_token, | |
| } | |
| def get_list_from_API(api_path, api_id, api_data): | |
| """ | |
| Retrieve and flatten a list of data from a LibreNMS API endpoint. | |
| Args: | |
| api_path (str): The API endpoint path to query | |
| api_id (str): The key to use as identifier in the flattened dictionary | |
| api_data (str): The key containing the list of items in the API response | |
| Returns: | |
| dict: A flattened dictionary mapping IDs to their corresponding data | |
| Returns empty dict if the API call fails | |
| Example: | |
| get_list_from_API('devices', 'device_id', 'devices') | |
| Returns: {device_id1: {device_data1}, device_id2: {device_data2}, ...} | |
| """ | |
| try: | |
| # Make API request | |
| response = requests.get(url=f"{lnms_api}/{api_path}", headers=request_headers) | |
| response.raise_for_status() # Raises HTTPError for bad responses (4XX, 5XX) | |
| # Parse JSON response | |
| get_api_list = response.json() | |
| # Flatten the response into a dictionary keyed by api_id | |
| reply = {subdict[api_id]: subdict for subdict in get_api_list[api_data]} | |
| return reply | |
| except requests.RequestException as e: | |
| # Handle any errors that occur during the API request | |
| print(f"Error fetching data from {api_path}: {e}") | |
| return {} | |
| def search_device_id(_id): | |
| """ | |
| Look up and return the system name for a given device ID. | |
| Args: | |
| _id: The device ID to look up | |
| Returns: | |
| str: The system name (sysName) of the device, or None if not found | |
| Note: | |
| Prints a warning message if the device ID is not found in the devices dictionary | |
| """ | |
| sysname = devices.get(_id, {}).get('sysName') | |
| if sysname is None: | |
| print(f"Warning: Device ID {_id} not found.") | |
| return sysname | |
| # Data Collection | |
| # -------------- | |
| # Fetch all network devices from LibreNMS | |
| devices = get_list_from_API('devices', 'device_id', 'devices') | |
| # Fetch all LLDP/CDP links between devices | |
| links = get_list_from_API('resources/links', 'id', 'links') | |
| # Graph Generation | |
| # --------------- | |
| # Initialize Graphviz diagram with specific properties | |
| draw = graphviz.Digraph('G', filename='lldp_topology', format='pdf') | |
| draw.attr(rankdir='LR') # Left to Right layout | |
| draw.attr('node', shape='box') # Use box shapes for nodes | |
| # Process Links and Create Graph | |
| # ---------------------------- | |
| # Iterate through all links and add them to the graph | |
| for key, value in links.items(): | |
| if isinstance(value, dict): | |
| # Get the names of devices on both ends of the link | |
| local_device = search_device_id(value['local_device_id']) | |
| remote_device = value.get('remote_hostname') | |
| # Only add the edge if we have valid devices on both ends | |
| if local_device and remote_device: | |
| # Add directed edge from local to remote device | |
| draw.edge(local_device, remote_device) | |
| # Generate Output | |
| # ------------- | |
| # Render the graph to a PDF file | |
| # This creates both a .pdf file and a source file in the Graphviz DOT language | |
| draw.render() | |
| print("Network topology PDF generated as 'lldp_topology.pdf'.") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment