Skip to content

Instantly share code, notes, and snippets.

@RezaAmbler
Created October 31, 2024 20:29
Show Gist options
  • Select an option

  • Save RezaAmbler/fcba2e949d7cab0775337d6fa73cc1f3 to your computer and use it in GitHub Desktop.

Select an option

Save RezaAmbler/fcba2e949d7cab0775337d6fa73cc1f3 to your computer and use it in GitHub Desktop.
Generator PDF report of LLDP connections from LibreNMS
#!/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