diff --git a/data/output/diagram.png b/data/output/diagram.png new file mode 100644 index 0000000..27959a1 Binary files /dev/null and b/data/output/diagram.png differ diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..39e5bd8 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +pyaml \ No newline at end of file diff --git a/src/netdiag/base.py b/src/netdiag/base.py index 1def400..999c201 100644 --- a/src/netdiag/base.py +++ b/src/netdiag/base.py @@ -3,11 +3,10 @@ from .domain.models import Topology from .parse.convert_raw import ( convert_raw_topology, ) +from .output.graphviz import generate_diagram +from .output.file_convert import make_yaml import logging -# from .make_res import make_result -# from .structures import Result - logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s" ) @@ -17,13 +16,10 @@ def run(): raw_devices = parse_csv("data/input/table.csv") # print(raw_devices) topology = convert_raw_topology(raw_devices) - print(topology) + # print(topology) - # 2) make structured result - # result = make_result(devices_raw, network_agg, network_interfaces) - - # # 3) output (for debug) - # print(result) + generate_diagram(topology, "data/output/diagram.png") + make_yaml(topology, "data/output/topology.yaml") if __name__ == "__main__": diff --git a/src/netdiag/output/__init__.py b/src/netdiag/output/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/netdiag/output/file_convert.py b/src/netdiag/output/file_convert.py new file mode 100644 index 0000000..9e444d3 --- /dev/null +++ b/src/netdiag/output/file_convert.py @@ -0,0 +1,30 @@ +import yaml + +from ..domain.models import Topology + +""" +Example: +links: +networks: + - A: [PC1.eth0, PC2.eth0] +meta: + id: host-host.csv + name: host-host.csv +nodes: +- role: host + name: PC1 + interfaces: + - eth0: + - ip: 10.0.12.1/24 + network: A +- role: host + name: PC2 + interfaces: + - eth0: + - ip: 10.0.12.2/24 + network: A +""" + + +def make_yaml(topology: Topology, output_path: str) -> None: + pass diff --git a/src/netdiag/output/graphviz.py b/src/netdiag/output/graphviz.py new file mode 100644 index 0000000..67c159b --- /dev/null +++ b/src/netdiag/output/graphviz.py @@ -0,0 +1,26 @@ +from ..domain.models import Topology +import graphviz + + +def generate_diagram(topology: Topology, output_path: str) -> None: + dot = graphviz.Graph(name="Network Topology", format="png", engine="neato") + dot.attr(overlap="false", splines="true") + + for device in topology.devices.values(): + shape = "box" + dot.node(device.name, label=device.name, shape=shape) + + for network in topology.networks.values(): + interfaces_with_device = [ + iface for iface in network.interfaces if iface.device is not None + ] + + for i, iface_a in enumerate(interfaces_with_device): + for iface_b in interfaces_with_device[i + 1 :]: + label = network.name or "" + dot.edge(iface_a.device.name, iface_b.device.name, label=label) + + output_path = output_path[:-4] if output_path.endswith(".png") else output_path + dot.render(output_path, cleanup=True) + + return diff --git a/src/netdiag/parse/convert_raw.py b/src/netdiag/parse/convert_raw.py index 1c37d48..08b3dbe 100644 --- a/src/netdiag/parse/convert_raw.py +++ b/src/netdiag/parse/convert_raw.py @@ -10,6 +10,7 @@ from ..domain.models import ( ) from . import RawDevices +import logging name_matching = { "DEVICE_TYPE": "Role", @@ -136,12 +137,15 @@ def assign_interfaces_to_networks( def convert_raw_topology(raw_devices: list[RawDevices]) -> Topology: topology = Topology() + logging.info(f"Parsing {len(raw_devices)} raw devices to devices") devices = parse_devices(raw_devices) + logging.info(f"Parsing interfaces from raw devices") add_interfaces(devices, raw_devices) for device in devices: topology.add_device(device) + logging.info(f"Parsing networks from raw devices") networks = parse_networks(devices, raw_devices) assign_interfaces_to_networks(networks, devices)