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)