diff --git a/docker-network-graph.py b/docker-network-graph.py index bd00804..b23ba80 100755 --- a/docker-network-graph.py +++ b/docker-network-graph.py @@ -10,8 +10,19 @@ from graphviz import Graph from graphviz.backend import FORMATS # colorlover.scales["12"]["qual"]["Paired"] converted to hex strings -COLORS = ["#1f78b4", "#33a02c", "#e31a1c", "#ff7f00", "#6a3d9a", "#b15928", "#a6cee3", "#b2df8a", "#fdbf6f", - "#cab2d6", "#ffff99"] +COLORS = [ + "#1f78b4", + "#33a02c", + "#e31a1c", + "#ff7f00", + "#6a3d9a", + "#b15928", + "#a6cee3", + "#b2df8a", + "#fdbf6f", + "#cab2d6", + "#ffff99", +] i = 0 @@ -58,7 +69,9 @@ def get_unique_color() -> str: return c -def get_networks(client: docker.DockerClient, verbose: bool) -> typing.Dict[str, Network]: +def get_networks( + client: docker.DockerClient, verbose: bool +) -> typing.Dict[str, Network]: networks: typing.Dict[str, Network] = {} for net in sorted(client.networks.list(), key=lambda k: k.name): @@ -83,7 +96,9 @@ def get_networks(client: docker.DockerClient, verbose: bool) -> typing.Dict[str, pass if verbose: - print(f"Network: {net.name} {'internal' if internal else ''} {'isolated' if isolated else ''} gw:{gateway}") + print( + f"Network: {net.name} {'internal' if internal else ''} {'isolated' if isolated else ''} gw:{gateway}" + ) color = get_unique_color() networks[net.name] = Network(net.name, gateway, internal, isolated, color) @@ -93,7 +108,9 @@ def get_networks(client: docker.DockerClient, verbose: bool) -> typing.Dict[str, return networks -def get_containers(client: docker.DockerClient, verbose: bool) -> (typing.List[Container], typing.List[Link]): +def get_containers( + client: docker.DockerClient, verbose: bool +) -> (typing.List[Container], typing.List[Link]): containers: typing.List[Container] = [] links: typing.List[Link] = [] @@ -101,7 +118,9 @@ def get_containers(client: docker.DockerClient, verbose: bool) -> (typing.List[C interfaces: typing.List[Interface] = [] # Iterate over container interfaces - for net_name, net_info in container.attrs["NetworkSettings"]["Networks"].items(): + for net_name, net_info in container.attrs["NetworkSettings"][ + "Networks" + ].items(): endpoint_id = net_info["EndpointID"] aliases = [] @@ -111,11 +130,13 @@ def get_containers(client: docker.DockerClient, verbose: bool) -> (typing.List[C if alias != container.id[:12] and alias != container.name: aliases.append(alias) - interfaces.append(Interface(endpoint_id, net_info['IPAddress'], aliases)) + interfaces.append(Interface(endpoint_id, net_info["IPAddress"], aliases)) links.append(Link(container.id, endpoint_id, net_name)) if verbose: - print(f"Container: {container.name} {''.join([iface.address for iface in interfaces])}") + print( + f"Container: {container.name} {''.join([iface.address for iface in interfaces])}" + ) containers.append(Container(container.id, container.name, interfaces)) @@ -130,12 +151,13 @@ def draw_network(g: Graph, net: Network): label += " | Containers isolated" label += "}" - g.node(f"network_{net.name}", - shape="record", - label=label, - fillcolor=net.color, - style="filled" - ) + g.node( + f"network_{net.name}", + shape="record", + label=label, + fillcolor=net.color, + style="filled", + ) def draw_container(g: Graph, c: Container): @@ -152,19 +174,21 @@ def draw_container(g: Graph, c: Container): label = f"{{ {c.name} | {{ {' | '.join(iface_labels)} }} }}" - g.node(f"container_{c.container_id}", - shape="record", - label=label, - fillcolor="#ff9999", - style="filled" - ) + g.node( + f"container_{c.container_id}", + shape="record", + label=label, + fillcolor="#ff9999", + style="filled", + ) def draw_link(g: Graph, networks: typing.Dict[str, Network], link: Link): - g.edge(f"container_{link.container_id}:{link.endpoint_id}", - f"network_{link.network_name}", - color=networks[link.network_name].color - ) + g.edge( + f"container_{link.container_id}:{link.endpoint_id}", + f"network_{link.network_name}", + color=networks[link.network_name].color, + ) def generate_graph(verbose: bool, file: str): @@ -175,9 +199,18 @@ def generate_graph(verbose: bool, file: str): if file: base, ext = os.path.splitext(file) - g = Graph(comment="Docker Network Graph", engine="sfdp", format=ext[1:], graph_attr=dict(splines="true")) + g = Graph( + comment="Docker Network Graph", + engine="sfdp", + format=ext[1:], + graph_attr=dict(splines="true"), + ) else: - g = Graph(comment="Docker Network Graph", engine="sfdp", graph_attr=dict(splines="true")) + g = Graph( + comment="Docker Network Graph", + engine="sfdp", + graph_attr=dict(splines="true"), + ) for _, network in networks.items(): draw_network(g, network) @@ -205,7 +238,9 @@ def graphviz_output_file(filename: str): if __name__ == "__main__": parser = argparse.ArgumentParser(description="Visualize docker networks.") parser.add_argument("-v", "--verbose", help="Verbose output", action="store_true") - parser.add_argument("-o", "--out", help="Write output to file", type=graphviz_output_file) + parser.add_argument( + "-o", "--out", help="Write output to file", type=graphviz_output_file + ) args = parser.parse_args() generate_graph(args.verbose, args.out)