Add command line parameters
This commit is contained in:
parent
f715389aa6
commit
ab88c610e1
5 changed files with 100 additions and 81 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -1,4 +1,3 @@
|
|||
/sandbox
|
||||
/*.gv
|
||||
/*.pdf
|
||||
*.gv
|
||||
*.pdf
|
||||
.idea
|
||||
|
|
2
Pipfile
2
Pipfile
|
@ -10,4 +10,4 @@ graphviz = "*"
|
|||
[dev-packages]
|
||||
|
||||
[requires]
|
||||
python_version = "3.7"
|
||||
python_version = "3"
|
||||
|
|
4
Pipfile.lock
generated
4
Pipfile.lock
generated
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "dd7e5eeba8f90bf7a95640eb165b90b96af947ddf7220542916f95709f01f14d"
|
||||
"sha256": "b980cd984b5794dc93711b11dcaadee33a6ee25a811c7aa8c8a6c7db32a78204"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
"python_version": "3.7"
|
||||
"python_version": "3"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
|
|
26
README.md
26
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.
|
144
docker-net-graph.py
Normal file → Executable file
144
docker-net-graph.py
Normal file → Executable file
|
@ -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 = '<br/>'.join([s for s in ['<font color="#777777"><i>network</i></font>', net_name, subnet, gateway] if s != None])
|
||||
|
||||
dot.node(net_node_id,
|
||||
shape='record',
|
||||
label="{<gw_iface> %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 = '<br/>'.join([s for s in ['<font color="#777777"><i>network</i></font>', net_name, subnet, gateway] if s is not None])
|
||||
|
||||
dot.node(net_node_id,
|
||||
shape='record',
|
||||
label="{<gw_iface> %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)
|
||||
|
|
Loading…
Reference in a new issue