From ab88c610e1e1d9fd6403033c97a341dd39381efb Mon Sep 17 00:00:00 2001 From: LeoVerto Date: Fri, 31 Aug 2018 04:50:58 +0200 Subject: [PATCH] Add command line parameters --- .gitignore | 5 +- Pipfile | 2 +- Pipfile.lock | 4 +- README.md | 26 +++++--- docker-net-graph.py | 144 +++++++++++++++++++++++--------------------- 5 files changed, 100 insertions(+), 81 deletions(-) mode change 100644 => 100755 docker-net-graph.py diff --git a/.gitignore b/.gitignore index c70d42d..a89052c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -/sandbox -/*.gv -/*.pdf +*.gv +*.pdf .idea diff --git a/Pipfile b/Pipfile index 69774d5..9fc8276 100644 --- a/Pipfile +++ b/Pipfile @@ -10,4 +10,4 @@ graphviz = "*" [dev-packages] [requires] -python_version = "3.7" +python_version = "3" diff --git a/Pipfile.lock b/Pipfile.lock index 7a9b551..069e78a 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,11 +1,11 @@ { "_meta": { "hash": { - "sha256": "dd7e5eeba8f90bf7a95640eb165b90b96af947ddf7220542916f95709f01f14d" + "sha256": "b980cd984b5794dc93711b11dcaadee33a6ee25a811c7aa8c8a6c7db32a78204" }, "pipfile-spec": 6, "requires": { - "python_version": "3.7" + "python_version": "3" }, "sources": [ { diff --git a/README.md b/README.md index 57a7097..85231dd 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,23 @@ -Docker Network Graph --------------------- +# Docker Network Graph Sample python script to draw graph of Docker networks and containers -Install/run -=========== +## Usage + usage: docker-net-graph.py [-h] [-v] [-o OUT] - #> git clone https://github.com/LeoVerto/docker-network-graph-poc.git - #> cd docker-network-graph-poc - #> pipenv install - #> pipenv run python docker-net-graph.py + Generate docker network graph. + + optional arguments: + -h, --help show this help message and exit + -v, --verbose Verbose output + -o OUT, --out OUT Write output to file + +In most cases what you want to run are the following couple commands: + + git clone https://github.com/LeoVerto/docker-network-graph-poc.git + cd docker-network-graph-poc + pipenv install + pipenv run python docker-net-graph.py -o output.gv + +This will end up generating a .pdf file containing the graph. \ No newline at end of file diff --git a/docker-net-graph.py b/docker-net-graph.py old mode 100644 new mode 100755 index c6ebbd0..3ccca07 --- a/docker-net-graph.py +++ b/docker-net-graph.py @@ -1,80 +1,90 @@ -from docker import Client - +#!/usr/bin/python3 import os -import pprint import json - +import argparse +from docker import Client from graphviz import Graph -dot = Graph(comment='Docker Network Graph', - graph_attr=dict( rankdir="TB", packmode='graph', pack='true') - ) -docker_client = Client(os.environ.get("DOCKER_HOST", "unix:///var/run/docker.sock")) +def generate_graph(verbose: bool, file: str): + dot = Graph(comment='Docker Network Graph', + graph_attr=dict(rankdir="TB", packmode='graph', pack='true') + ) -def dump_json(obj): - print(json.dumps(obj, indent=4)) + docker_client = Client(os.environ.get("DOCKER_HOST", "unix:///var/run/docker.sock")) -for c in sorted(docker_client.containers()): - name = c['Names'][0] - container_id = c['Id'] - - node_id = 'container_%s' % container_id - - iface_labels = [] - - for net_name, net_info in c['NetworkSettings']['Networks'].items(): - label_iface = "<%s> %s" % (net_info['EndpointID'], net_info['IPAddress']) - - iface_labels.append(label_iface) - - print('|'.join(iface_labels)) - - - dot.node(node_id, - shape='record', - label="{ %s | { %s } }" % (name, '|'.join(iface_labels)), - fillcolor='#ff9999', - style='filled') - - + def dump_json(obj): + print(json.dumps(obj, indent=4)) -for net in docker_client.networks(): - net_name = net['Name'] - - try: - gateway = net['IPAM']['Config'][0]['Gateway'] - except IndexError: - gateway = None + for c in docker_client.containers(): + name = c['Names'][0] + container_id = c['Id'] - try: - subnet = net['IPAM']['Config'][0]['Subnet'] - except IndexError: - subnet = None + node_id = 'container_%s' % container_id - print("Network: %s %s gw:%s" % ( net_name, subnet,gateway)) + iface_labels = [] - net_node_id = "net_%s" % (net_name,) - - net_label_html = '
'.join([s for s in ['network', net_name, subnet, gateway] if s != None]) - - dot.node(net_node_id, - shape='record', - label="{ %s| %s }" % (gateway, net_name), - fillcolor='#99ff99', - style='filled') + for net_name, net_info in c['NetworkSettings']['Networks'].items(): + label_iface = "<%s> %s" % (net_info['EndpointID'], net_info['IPAddress']) + + iface_labels.append(label_iface) + + if verbose: + print('|'.join(iface_labels)) + + dot.node(node_id, + shape='record', + label="{ %s | { %s } }" % (name, '|'.join(iface_labels)), + fillcolor='#ff9999', + style='filled') + + for net in docker_client.networks(): + net_name = net['Name'] + + try: + gateway = net['IPAM']['Config'][0]['Gateway'] + except IndexError: + gateway = None + + try: + subnet = net['IPAM']['Config'][0]['Subnet'] + except IndexError: + subnet = None + + if verbose: + print("Network: %s %s gw:%s" % (net_name, subnet, gateway)) + + net_node_id = "net_%s" % (net_name,) + + net_label_html = '
'.join([s for s in ['network', net_name, subnet, gateway] if s is not None]) + + dot.node(net_node_id, + shape='record', + label="{ %s| %s }" % (gateway, net_name), + fillcolor='#99ff99', + style='filled') + + for container_id, container in sorted(net['Containers'].items()): + if verbose: + dump_json(container) + if verbose: + print(" * ", container['Name'], container['IPv4Address'], container['IPv6Address']) + + container_node_id = 'container_%s' % container_id + + container_iface_ref = "%s:%s" % (container_node_id, container['EndpointID']) + + dot.edge(container_iface_ref, net_node_id+":gw_iface") + + print(dot.source) + if file: + dot.render(file) - for container_id, container in sorted(net['Containers'].items()): - dump_json(container) - print(" * ", container['Name'], container['IPv4Address'], container['IPv6Address']) - - container_node_id = 'container_%s' % container_id - - container_iface_ref = "%s:%s" % (container_node_id, container['EndpointID']) - - dot.edge(container_iface_ref, net_node_id+":gw_iface") - -print(dot.source) -dot.render('dng.gv') - +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Generate docker network graph.") + parser.add_argument("-v", "--verbose", help="Verbose output", action="store_true") + parser.add_argument("-o", "--out", help="Write output to file", type=str) + args = parser.parse_args() + + generate_graph(args.verbose, args.out)