Files
python-don/openstack_dashboard/don/ovs/plot.py
Arie 4f7d1de85e More fixes to ovs modules
Because this code deserves to be beautiful.

Change-Id: I0cc85d9a1103d4d4d7a19bf617838179197f9c90
2016-09-27 12:20:03 +03:00

918 lines
36 KiB
Python

# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import argparse
import pprint
import random
import re
import subprocess
import sys
from common import debug
from common import get_intf_ip
from common import get_ip_network
from common import get_subnet
from common import get_vlan_tag
from common import load_json
from common import settings
from common import warning
class DotGenerator(object):
"""Generates an SVG file showing the network internals of
a compute node.
"""
def __init__(self, in_json_filename,
compute_dot_file, compute_svg_file,
network_dot_file, network_svg_file,
combined_dot_file, combined_svg_file,
highlight_file):
self.json_filename = in_json_filename
self.compute_dot_file = compute_dot_file
self.compute_svg_file = compute_svg_file
self.network_dot_file = network_dot_file
self.network_svg_file = network_svg_file
self.combined_dot_file = combined_dot_file
self.combined_svg_file = combined_svg_file
self.highlight_file = highlight_file
settings['debug'] = True
self.highlight_info = None
if highlight_file:
self.highlight_info = load_json(self.highlight_file)
if not self.highlight_info.get('net_info'):
self.highlight_info['net_info'] = {'pass': [],
'fail': []
}
self.info = load_json(self.json_filename)
self.outfile = None
self.colors = {
'vms': '#ff9933',
'tap': '#99ffff',
'qbr': '#9966ff',
'br-int': '#ff6666',
'br-tun': '#ff6666',
'qvb': '#ffcc00',
'qvo': '#ffcc00',
'tun': '#ffcc00',
'int': '#ffcc00',
'routers': '#ff9933',
'vlan': [],
'error': '#f00000',
'edge': '#0066cc',
'dontcare': '#909090',
'pass': '#b2f379',
'fail': '#f00000',
'edge_pass': '#009900',
'floating_ip': '#b3ffb3',
}
self.__set_vlan_color_table()
pprint.pprint(self.info)
def __port_pass(self, port):
if self.highlight_file:
if port.replace('.', '') == self.highlight_info['src_info']['ip'].replace('.', '') or \
port.replace('.', '') == self.highlight_info['dst_info']['ip'].replace('.', ''):
return self.highlight_info['ping_pass']
if self.highlight_info['src_info'].has_key('pass') and port in self.highlight_info['src_info']['pass'] or \
self.highlight_info['dst_info'].has_key('pass') and port in self.highlight_info['dst_info']['pass'] or \
self.highlight_info['net_info'].has_key('pass') and port in self.highlight_info['net_info']['pass']:
return True
return False
def __port_fail(self, port):
if self.highlight_file:
if port.replace('.', '') == self.highlight_info['src_info']['ip'].replace('.', '') or \
port.replace('.', '') == self.highlight_info['dst_info']['ip'].replace('.', ''):
return not self.highlight_info['ping_pass']
if self.highlight_info['src_info'].has_key('fail') and port in self.highlight_info['src_info']['fail'] or \
self.highlight_info['dst_info'].has_key('fail') and port in self.highlight_info['dst_info']['fail'] or \
self.highlight_info['net_info'].has_key('fail') and port in self.highlight_info['net_info']['fail']:
return True
return False
def __get_edge_color(self, src_tag, dst_tag):
if not self.highlight_file:
return self.__get_color('edge')
sport = src_tag
dport = dst_tag
m = re.search('\S+:(\S+)', src_tag)
if m:
sport = m.group(1)
m = re.search('\S+:(\S+)', dst_tag)
if m:
dport = m.group(1)
spass = self.__port_pass(sport)
dpass = self.__port_pass(dport)
sfail = self.__port_fail(sport)
dfail = self.__port_fail(dport)
debug('%s (p%d f%d) -> %s (p%d f%d)' % (sport, spass, sfail, dport,
dpass, dfail))
if spass or dpass:
return self.colors['edge_pass']
if sfail and dfail:
return self.colors['fail']
return self.colors['dontcare']
def __get_color(self, tag):
if self.highlight_file:
return self.colors['dontcare']
else:
return self.colors[tag]
def __hsv_to_rgb(self, h, s, v):
h_i = int((h * 6))
f = h * 6 - h_i
p = v * (1 - s)
q = v * (1 - f * s)
t = v * (1 - (1 - f) * s)
if h_i == 0:
r, g, b = v, t, p
if h_i == 1:
r, g, b = q, v, p
if h_i == 2:
r, g, b = p, v, t
if h_i == 3:
r, g, b = p, q, v
if h_i == 4:
r, g, b = t, p, v
if h_i == 5:
r, g, b = v, p, q
return [r * 256, g * 256, b * 256]
def __set_vlan_color_table(self):
i = 20
random.seed(1)
while i > 0:
colors = self.__hsv_to_rgb(random.random(), 0.5, 0.95)
colors = [hex(int(x)).split('x')[1] for x in colors]
colors = ''.join(x for x in colors)
self.colors['vlan'].append('#' + colors)
i -= 1
debug(pprint.pformat(self.colors['vlan']))
# port becomes relevant only if highlight_file is specified.
def __get_vlan_color(self, tag, port='dummy'):
if self.highlight_file:
if self.__port_pass(port):
return self.colors['pass']
elif self.__port_fail(port):
return self.colors['fail']
else:
return self.colors['dontcare']
else:
total_colors = len(self.colors['vlan'])
return self.colors['vlan'][int(tag) % total_colors]
def __get_total_vm_port_count(self):
port_count = 0
for vm in self.info['vms'].keys():
port_count += len(self.info['vms'][vm]['src_bridge'])
return port_count
# TODO XXX needs some work to handle different subnet mask length. LPM needs
# to be implemented!
def __get_network_id(self, ip):
networks = self.info['networks']
subnet = get_subnet(ip)
for net in networks.keys():
if re.search(subnet, networks[net]['ip']):
return net
return None
def __get_network_name(self, ip):
network_id = self.__get_network_id(ip)
return self.info['networks'][network_id]['name']
def __get_tap_interface(self, namespace, qr_intf):
namespaces = self.info['namespaces']
ip = namespaces[namespace]['interfaces'][qr_intf]
network_id = self.__get_network_id(ip)
if not network_id:
return 'No TAP! 1'
qdhcp = 'qdhcp-' + network_id
if not namespaces.has_key(qdhcp):
return 'No TAP! 2'
for intf in namespaces[qdhcp]['interfaces'].keys():
return (qdhcp, intf)
pass
def __get_router_port_count(self, router, port_type='qr'):
port_count = 0
router_id = self.info['routers'][router]['id']
qrouter = 'qrouter-' + router_id
namespaces = self.info['namespaces']
for nms in namespaces.keys():
if re.search('^' + qrouter, nms):
for intf in namespaces[nms]['interfaces'].keys():
if re.search('^' + port_type, intf):
port_count += 1
return port_count
def __get_total_port_count(self, port_type='qr'):
port_count = 0
for router in self.info['routers'].keys():
port_count += self.__get_router_port_count(router, port_type)
return port_count
def __get_total_dhcp_port_count(self):
port_count = 0
namespaces = self.info['namespaces']
for nms in namespaces.keys():
if re.search('^qdhcp-', nms):
for intf in namespaces[nms]['interfaces'].keys():
if re.search('^tap', intf):
port_count += 1
return port_count
def __html_row_open(self):
print('<TR>')
def __html_row_close(self):
print('</TR>')
def __html_row(self, name, rspan, cspan, color, tag=None):
# tags do not allow "-" (dash) in DOT language. Convert to "_"
# (underscore)
if tag:
print('<TD ROWSPAN="%d" COLSPAN="%d" BGCOLOR="%s" PORT="%s">%s</TD>' % (rspan, cspan, color, tag.replace('-', '_'), name))
else:
print('<TD ROWSPAN="%d" COLSPAN="%d" BGCOLOR="%s">%s</TD>' % (rspan, cspan, color, name))
pass
def __html_edge(selft, src_tag, dst_tag, color, penwidth="4", style=None):
src_tag = src_tag.replace('-', '_')
dst_tag = dst_tag.replace('-', '_')
if not style:
print('%s:s -> %s:n [color = "%s", penwidth = "%s"]' % (src_tag,
dst_tag,
color,
penwidth))
else:
print('%s:s -> %s:n [color = "%s", penwidth = "%s", style="%s"]' % (src_tag,
dst_tag,
color,
penwidth,
style))
def __digraph_open(self, tag):
msg = 'digraph DON_' + tag + ' {' + \
'''
graph [fontsize=10 fontname="Helvetica"];
node [fontsize=10 fontname="Helvetica"];
rankdir = TB;
ranksep = 1;
concentrate = true;
compound = true;
edge [dir=none]
'''
print(msg)
def __digraph_close(self):
msg = '\n}\n'
print(msg)
def __cluster_name(self, tag, col_span, color="white"):
self.__html_row_open()
port = tag.replace(' ', '').replace('-', '_')
print('<TD COLSPAN="%d" BORDER="0" BGCOLOR="%s" PORT="%s">%s</TD>' % (col_span, color, port, tag))
self.__html_row_close()
def __cluster_open_plain(self, tag, label=None):
print('subgraph cluster_%s {' % (tag))
print('style=filled')
if label:
print('label="%s"' % (label))
def __cluster_close_plain(self):
print('}\n')
def __cluster_open(self, tag, color="white"):
print('subgraph cluster_%s {' % (tag))
print('%s [ shape = plaintext, label = <' % (tag))
print('<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="5" CELLPADDING="5" BGCOLOR="%s">' % (color))
pass
def __cluster_close(self):
print('</TABLE>>];\n')
print('}\n')
pass
def __plot_title_edges(self, tag):
if tag == 'compute':
src_tag = 'ComputeNode'
dst_tag = 'VMs'
else:
src_tag = 'NetworkNode'
dst_tag = 'br_ex'
self.__html_edge(src_tag, dst_tag,
self.__get_color('edge'), style="invis")
def __plot_vms(self):
col_span = self.__get_total_vm_port_count()
row_span = 1
self.__cluster_open('VMs')
self.__cluster_name('VMs', col_span)
# Plot each VM at a time
self.__html_row_open()
for vm in sorted(self.info['vms'].keys()):
col_span = len(self.info['vms'][vm]['src_bridge'])
if self.info['floating_ips'].get(self.info['vms'][vm]['uuid']):
col_span = col_span + 1
self.__html_row(vm, row_span, col_span, self.__get_color('vms'))
self.__html_row_close()
# Plot the networks for each port
self.__html_row_open()
col_span = 1
for vm in sorted(self.info['vms'].keys()):
floating_ip_info = self.info['floating_ips'].get(
self.info['vms'][vm]['uuid'])
if floating_ip_info:
network = floating_ip_info.get('pool')
self.__html_row('Floating -' + network, row_span,
col_span, self.colors['floating_ip'])
for bridge in sorted(self.info['vms'][vm]['src_bridge']):
tag = get_vlan_tag(self.info, bridge)
ip = get_intf_ip(self.info, bridge)
network = get_ip_network(self.info, vm, ip)
color = self.__get_vlan_color(tag)
if re.search('unknown', network):
color = self.__get_color('error')
self.__html_row(network, row_span, col_span, color)
self.__html_row_close()
# Plot the IPs for each port
self.__html_row_open()
for vm in sorted(self.info['vms'].keys()):
floating_ip_info = self.info['floating_ips'].get(
self.info['vms'][vm]['uuid'])
if floating_ip_info:
ip = floating_ip_info.get('floating_ip')
self.__html_row(ip, row_span, col_span, self.colors[
'floating_ip'], ip.replace('.', ''))
for bridge in sorted(self.info['vms'][vm]['src_bridge']):
tag = get_vlan_tag(self.info, bridge)
ip = get_intf_ip(self.info, bridge)
color = self.__get_vlan_color(tag, ip)
if re.search('x.x.x.x', ip):
color = self.__get_color('error')
self.__html_row(ip, row_span, col_span,
color, ip.replace('.', ''))
self.__html_row_close()
self.__cluster_close()
pass
def __plot_linux_bridge(self):
row_span = 1
col_span = self.__get_total_vm_port_count()
self.__cluster_open('LinuxBridge')
self.__cluster_name('Linux Bridge', col_span)
# There must be one linuxbridge entity per VM port.
col_span = 1
# First, the tap devices
self.__html_row_open()
for vm in sorted(self.info['vms'].keys()):
for bridge in sorted(self.info['vms'][vm]['src_bridge']):
if self.info['brctl'].has_key(bridge):
for dev in self.info['brctl'][bridge]['interfaces']:
if re.search('^tap', dev):
tag = get_vlan_tag(self.info, bridge)
self.__html_row(dev, row_span, col_span,
self.__get_vlan_color(tag, dev), dev)
break
self.__html_row_close()
# Second, the linuxbridges
self.__html_row_open()
for vm in sorted(self.info['vms'].keys()):
for bridge in sorted(self.info['vms'][vm]['src_bridge']):
if self.info['brctl'].has_key(bridge):
tag = get_vlan_tag(self.info, bridge)
self.__html_row(bridge, row_span, col_span,
self.__get_vlan_color(tag, bridge), bridge)
self.__html_row_close()
# Third, the qvb (one part of eth-pair) devices
self.__html_row_open()
for vm in sorted(self.info['vms'].keys()):
for bridge in sorted(self.info['vms'][vm]['src_bridge']):
if self.info['brctl'].has_key(bridge):
for dev in self.info['brctl'][bridge]['interfaces']:
if re.search('^qvb', dev):
tag = get_vlan_tag(self.info, bridge)
self.__html_row(dev, row_span, col_span,
self.__get_vlan_color(tag, dev), dev)
break
self.__html_row_close()
self.__cluster_close()
pass
def __plot_br_int_compute(self):
br_int = self.info['bridges']['br-int']
row_span = 1
col_span = self.__get_total_vm_port_count()
self.__cluster_open('compute_br_int')
self.__cluster_name('OVS br_int', col_span)
# The qvo (pairs with qvb part in linuxbridge) devices
col_span = 1
self.__html_row_open()
for vm in sorted(self.info['vms'].keys()):
for bridge in sorted(self.info['vms'][vm]['src_bridge']):
qvo_port = bridge.replace('qbr', 'qvo')
if br_int['ports'].has_key(qvo_port):
port_id = '[' + br_int['ports'][qvo_port]['id'] + '] '
tag = br_int['ports'][qvo_port]['tag']
self.__html_row(port_id + qvo_port, row_span, col_span,
self.__get_vlan_color(tag, qvo_port), qvo_port)
self.__html_row_close()
# The vlan tags for each of the devices
col_span = 1
self.__html_row_open()
for vm in sorted(self.info['vms'].keys()):
for bridge in sorted(self.info['vms'][vm]['src_bridge']):
qvo_port = bridge.replace('qbr', 'qvo')
if br_int['ports'].has_key(qvo_port):
tag = br_int['ports'][qvo_port]['tag']
self.__html_row('VLAN tag:' + tag, row_span, col_span,
self.__get_vlan_color(tag),
qvo_port + 'tag_' + tag)
self.__html_row_close()
col_span = self.__get_total_vm_port_count()
# Display the patch-tun port
self.__html_row_open()
tun_port = 'patch-tun'
if br_int['ports'].has_key(tun_port):
port_id = '[' + br_int['ports'][tun_port]['id'] + '] '
self.__html_row(port_id + tun_port, row_span, col_span,
self.__get_color('tun'), tun_port)
else:
self.__html_row(tun_port, row_span, col_span,
self.__get_color('error'), tun_port)
self.__html_row_close()
self.__cluster_close()
def __plot_br_ex_to_br_int(self):
namespaces = self.info['namespaces']
for nms in namespaces.keys():
if not re.search('^qrouter-', nms):
continue
if not namespaces[nms].has_key('interfaces'):
warning('namespace %s does not have any interface' % nms)
continue
qg_intf = None
for intf in namespaces[nms]['interfaces'].keys():
if re.search('^qg-', intf):
qg_intf = intf
break
for intf in namespaces[nms]['interfaces'].keys():
if re.search('^qr-', intf):
src_tag = 'br_ex:' + qg_intf
dst_tag = 'network_br_int:' + intf
self.__html_edge(src_tag, dst_tag,
self.__get_color('edge'))
def __plot_br_ex_network(self):
routers = self.info['routers']
namespaces = self.info['namespaces']
br_ex = self.info['bridges']['br-ex']
row_span = 1
max_col_span = self.__get_total_port_count(port_type='qg')
self.__cluster_open('br_ex')
self.__cluster_name('OVS br_ex', max_col_span)
# Display the router name associated with each qg port
self.__html_row_open()
for router in sorted(routers.keys()):
col_span = self.__get_router_port_count(router, port_type='qg')
self.__html_row(router, row_span, col_span,
self.__get_color('routers'), router)
self.__html_row_close()
# Display the ips for each qg port
self.__html_row_open()
for router in sorted(routers.keys()):
col_span = self.__get_router_port_count(router, port_type='qg')
qrouter = 'qrouter-' + routers[router]['id']
for nms in namespaces.keys():
if re.search('^' + qrouter, nms):
for intf in namespaces[nms]['interfaces'].keys():
if re.search('^qg-', intf):
ip = namespaces[nms]['interfaces'][intf]
self.__html_row(ip, row_span, col_span,
self.__get_color('routers'), ip)
self.__html_row_close()
# For each router, print the qg- interfaces
self.__html_row_open()
for router in sorted(routers.keys()):
col_span = self.__get_router_port_count(router, port_type='qg')
qrouter = 'qrouter-' + routers[router]['id']
for nms in namespaces.keys():
if re.search('^' + qrouter, nms):
for intf in namespaces[nms]['interfaces'].keys():
if re.search('^qg-', intf):
port_id = '[' + br_ex['ports'][intf]['id'] + '] '
self.__html_row(port_id + intf, row_span, col_span,
self.__get_color('routers'), intf)
self.__html_row_close()
self.__cluster_close()
def __plot_br_int_network(self):
routers = self.info['routers']
namespaces = self.info['namespaces']
br_int = self.info['bridges']['br-int']
row_span = 1
# max_col_span = self.__get_total_port_count(port_type='qr') + \
# self.__get_total_dhcp_port_count()
max_col_span = self.__get_total_port_count(port_type='qr') * 2
col_span = max_col_span
self.__cluster_open('network_br_int')
self.__cluster_name('OVS br_int', col_span)
# For each router, print the qr- and tap (dhcp) interfaces
temp_info = []
col_span = 1
self.__html_row_open()
for router in sorted(routers.keys()):
qrouter = 'qrouter-' + routers[router]['id']
for nms in namespaces.keys():
if re.search('^' + qrouter, nms):
for intf in namespaces[nms]['interfaces'].keys():
if re.search('^qr-', intf):
tag = br_int['ports'][intf]['tag']
port_id = '[' + br_int['ports'][intf]['id'] + '] '
color = self.__get_vlan_color(tag, intf)
self.__html_row(
port_id + intf, row_span,
col_span, color, intf)
# now plot the corresponding tap interface
(tap_nms, tap) = self.__get_tap_interface(nms,
intf)
tag = br_int['ports'][tap]['tag']
color = self.__get_vlan_color(tag, tap)
port_id = '[' + br_int['ports'][tap]['id'] + '] '
self.__html_row(
port_id + tap, row_span, col_span, color, tap)
a = {
'qr_intf': intf,
'tap_intf': tap,
'qr_ip': namespaces[nms]['interfaces'][intf],
'tap_ip': namespaces[tap_nms]['interfaces'][tap],
}
temp_info.append(a)
self.__html_row_close()
# The vlan tags for each of the qr- and tap ports
col_span = 1
self.__html_row_open()
for entry in temp_info:
qr_intf = entry['qr_intf']
tap_intf = entry['tap_intf']
tag = br_int['ports'][qr_intf]['tag']
self.__html_row('VLAN tag:' + tag, row_span, col_span,
self.__get_vlan_color(tag), qr_intf + 'tag_' + tag)
tag = br_int['ports'][tap_intf]['tag']
self.__html_row('VLAN tag:' + tag, row_span, col_span,
self.__get_vlan_color(tag),
tap_intf + 'tag_' + tag)
self.__html_row_close()
# Display the ips with each of the qr- and tap ports
self.__html_row_open()
for entry in temp_info:
qr_intf = entry['qr_intf']
qr_ip = entry['qr_ip']
tap_intf = entry['tap_intf']
tap_ip = entry['tap_ip']
tag = br_int['ports'][qr_intf]['tag']
self.__html_row(qr_ip, row_span, col_span,
self.__get_vlan_color(tag),
qr_intf + qr_ip)
tag = br_int['ports'][tap_intf]['tag']
self.__html_row(tap_ip, row_span, col_span,
self.__get_vlan_color(tag),
tap_intf + tap_ip)
self.__html_row_close()
# The network names (private1, private2, etc.)
col_span = 2
self.__html_row_open()
for entry in temp_info:
network_name = self.__get_network_name(entry['qr_ip'])
tag = br_int['ports'][entry['qr_intf']]['tag']
self.__html_row(network_name, row_span, col_span,
self.__get_vlan_color(tag), network_name)
self.__html_row_close()
# The routers in the system
self.__html_row_open()
for router in sorted(self.info['routers'].keys()):
# For each qr port that is also a tap port (for dhcp)
col_span = self.__get_router_port_count(router, port_type='qr') * 2
self.__html_row(router, row_span, col_span,
self.__get_color('routers'), router)
self.__html_row_close()
# Display the patch-tun port
self.__html_row_open()
tun_port = 'patch-tun'
debug('max_col_span 2: ' + str(max_col_span))
if br_int['ports'].has_key(tun_port):
port_id = '[' + br_int['ports'][tun_port]['id'] + '] '
self.__html_row(port_id + tun_port, row_span, max_col_span,
self.__get_color('tun'), tun_port)
else:
self.__html_row(tun_port, row_span, max_col_span,
self.__get_color('error'), tun_port)
self.__html_row_close()
self.__cluster_close()
def __plot_br_tun(self, tag):
br_tun = self.info['bridges']['br-tun']
row_span = 1
col_span = self.__get_total_vm_port_count()
self.__cluster_open(tag + '_br_tun')
self.__cluster_name('OVS br_tun', col_span)
# Display the patch-int port
col_span = self.__get_total_vm_port_count()
self.__html_row_open()
int_port = 'patch-int'
if br_tun['ports'].has_key(int_port):
port_id = '[' + br_tun['ports'][int_port]['id'] + '] '
self.__html_row(port_id + int_port, row_span,
col_span, self.__get_color('int'), int_port)
else:
self.__html_row(int_port, row_span, col_span,
self.__get_color('error'), int_port)
self.__html_row_close()
self.__cluster_close()
def __plot_vms_to_linuxbridge(self):
brctl = self.info['brctl']
for vm in sorted(self.info['vms'].keys()):
for bridge in sorted(self.info['vms'][vm]['src_bridge']):
ip = get_intf_ip(self.info, bridge)
if brctl.has_key(bridge):
for dev in brctl[bridge]['interfaces']:
if re.search('^tap', dev):
src_tag = 'VMs:' + ip.replace('.', '')
dst_tag = 'LinuxBridge:' + dev
color = self.__get_edge_color(src_tag, dst_tag)
self.__html_edge(src_tag, dst_tag, color)
break
def __plot_linuxbridge_to_br_int(self):
brctl = self.info['brctl']
br_int = self.info['bridges']['br-int']
for vm in sorted(self.info['vms'].keys()):
for bridge in sorted(self.info['vms'][vm]['src_bridge']):
if brctl.has_key(bridge):
for dev in brctl[bridge]['interfaces']:
if re.search('^qvb', dev):
qvo_port = bridge.replace('qbr', 'qvo')
if br_int['ports'].has_key(qvo_port):
src_tag = 'LinuxBridge:' + dev
dst_tag = 'compute_br_int:' + qvo_port
color = self.__get_edge_color(src_tag, dst_tag)
self.__html_edge(src_tag, dst_tag, color)
break
def __plot_br_int_to_br_tun(self, tag):
br_int = self.info['bridges']['br-int']['ports']
br_tun = self.info['bridges']['br-tun']['ports']
tun_port = 'patch-tun'
int_port = 'patch-int'
if br_int.has_key(tun_port) and br_tun.has_key(int_port):
tun_peer = br_int[tun_port]['interfaces'][
tun_port].get('options', None)
int_peer = br_tun[int_port]['interfaces'][
int_port].get('options', None)
if tun_peer and int_peer:
if re.search('peer=' + int_port, tun_peer) and \
re.search('peer=' + tun_port, int_peer):
src_tag = tag + '_br_int:' + tun_port
dst_tag = tag + '_br_tun:' + int_port
self.__html_edge(src_tag, dst_tag,
self.__get_color('edge'))
return
def plot_combined(self):
self.outfile = open(self.combined_dot_file, 'w')
sys.stdout = self.outfile
tag = 'DON'
self.__digraph_open(tag)
self.__cluster_open_plain('DONComputeNode')
self.plot_compute_node()
self.__cluster_close_plain()
self.__cluster_open_plain('DONNetworkNode')
self.plot_network_node()
self.__cluster_close_plain()
self.__digraph_close()
self.outfile.close()
sys.stdout = sys.__stdout__
def plot_compute_node(self):
tag = 'compute'
redirected = False
if sys.stdout == sys.__stdout__:
self.outfile = open(self.compute_dot_file, "w")
sys.stdout = self.outfile
redirected = True
self.__digraph_open(tag)
# Title
self.__cluster_open('ComputeNode', 'red')
self.__cluster_name('Compute Node', 1, 'yellow')
self.__cluster_close()
# Plot nodes
self.__cluster_open_plain('Nova')
self.__plot_vms()
self.__plot_linux_bridge()
self.__cluster_close_plain()
self.__cluster_open_plain('OVS')
self.__plot_br_int_compute()
self.__plot_br_tun(tag)
self.__cluster_close_plain()
# Plot edges
self.__plot_title_edges(tag)
self.__plot_vms_to_linuxbridge()
self.__plot_linuxbridge_to_br_int()
self.__plot_br_int_to_br_tun(tag)
if redirected:
self.__digraph_close()
self.outfile.close()
sys.stdout = sys.__stdout__
def generate_compute_svg(self):
cmd = ['/usr/bin/dot', '-Tsvg', self.compute_dot_file,
'-o', self.compute_svg_file]
debug(pprint.pformat(cmd))
subprocess.call(cmd)
debug('Done generating compute SVG')
def plot_network_node(self):
tag = 'network'
redirected = False
if sys.stdout == sys.__stdout__:
self.outfile = open(self.network_dot_file, "w")
sys.stdout = self.outfile
redirected = True
self.__digraph_open(tag)
self.__cluster_open('NetworkNode', 'red')
self.__cluster_name('Network Node', 1, 'yellow')
self.__cluster_close()
# Plot nodes
self.__cluster_open_plain('OVS')
self.__plot_br_ex_network()
self.__plot_br_int_network()
self.__plot_br_tun(tag)
self.__cluster_close_plain()
# Plot edges
self.__plot_title_edges(tag)
self.__plot_br_int_to_br_tun(tag)
self.__plot_br_ex_to_br_int()
if redirected:
self.__digraph_close()
self.outfile.close()
sys.stdout = sys.__stdout__
def generate_network_svg(self):
cmd = ['/usr/bin/dot', '-Tsvg', self.network_dot_file,
'-o', self.network_svg_file]
debug(pprint.pformat(cmd))
subprocess.call(cmd)
debug('Done generating network SVG')
def generate_combined_svg(self):
cmd = ['/usr/bin/dot', '-Tsvg', self.combined_dot_file,
'-o', self.combined_svg_file]
debug(pprint.pformat(cmd))
subprocess.call(cmd)
debug('Done generating network SVG')
def check_args():
parser = argparse.ArgumentParser(
description='Plot the compute node network internals',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('--debug', dest='debug',
help='Enable debugging',
default=True, action='store_true')
parser.add_argument('--info_file', dest='info_file',
help='Info is read in JSON format in this file',
default="don.json", type=str)
parser.add_argument('--compute_file', dest='compute_file',
help='[compute_file].dot and [compute_file].svg will be generated for compute node', default="compute", type=str)
parser.add_argument('--network_file', dest='network_file',
help='[network_file].dot and [network_file].svg will be generated for network node', default="network", type=str)
parser.add_argument('--combined_file', dest='combined_file',
help='[combined_file].dot and [combined_file].svg will be generated', default="don", type=str)
parser.add_argument('--highlight_file', dest='highlight_file',
help='pass and fail node are specified in this file',
default=None, type=str)
args = parser.parse_args()
settings['debug'] = args.debug
settings['info_file'] = args.info_file
settings['compute_dot_file'] = args.compute_file + '.dot'
settings['compute_svg_file'] = args.compute_file + '.svg'
settings['network_dot_file'] = args.network_file + '.dot'
settings['network_svg_file'] = args.network_file + '.svg'
settings['combined_dot_file'] = args.combined_file + '.dot'
settings['combined_svg_file'] = args.combined_file + '.svg'
settings['highlight_file'] = args.highlight_file
def main():
check_args()
plotter = DotGenerator(settings['info_file'],
settings['compute_dot_file'],
settings['compute_svg_file'],
settings['network_dot_file'],
settings['network_svg_file'],
settings['combined_dot_file'],
settings['combined_svg_file'],
settings['highlight_file'],
)
if not settings['highlight_file']:
plotter.plot_compute_node()
plotter.generate_compute_svg()
plotter.plot_network_node()
plotter.generate_network_svg()
plotter.plot_combined()
plotter.generate_combined_svg()
if __name__ == "__main__":
main()