--- a/bin/pvl.hosts-graph Mon Mar 31 16:36:45 2014 +0300
+++ b/bin/pvl.hosts-graph Mon Mar 31 17:14:51 2014 +0300
@@ -182,6 +182,8 @@
hosts_by_ethernet = { } # ethernet: host
hosts_by_location = { } # (domain, location): host
+ nodes_port = { } # (local, int(local_port)): remote
+ nodes_out = { } # local: {remote}
links_out = { } # (local, remote): local_port
links_in = { } # (remote, local): remote_port
@@ -258,6 +260,8 @@
# directional mapping
links_out[(local_node, remote_node)] = local_port
+ nodes_port[(local_node, port)] = remote_node
+ nodes_out.setdefault(local_node, set()).add(remote_node)
# bidirectional mappings
remote_port = remote_attrs['port']
@@ -287,63 +291,6 @@
links[reverse] = (remote_untag, remote_tagged, local_untag)
- # second graph: bridge
- if not options.graph_bridge :
- bridge = { }
- elif 'bridge' in host_attrs :
- bridge = host_attrs['bridge']
- else :
- bridge = { }
-
- for port, ethernets in bridge.iteritems() :
- local_node = host
- local_port = port
-
- for ethernet in ethernets :
- if ethernet in hosts_by_ethernet :
- remote_node = remote_host = hosts_by_ethernet[ethernet]
-
- remote_label = remote_host.location or str(remote_host)
-
- log.info("%s:%s bridge %s = %s (%s)", host, port, ethernet, remote_host, remote_label)
- else :
- remote_node = remote_host = None
-
- if not remote_host :
- continue
-
- if remote_node not in nodes :
- log.debug("%s:%s: lazy-add remote %s (%s)", host, port, remote_node, remote_label)
-
- nodes[remote_node] = remote_label
-
- # unknown vlans
- link_vlans = None
-
- # directional link
- links_out[(local_node, remote_node)] = local_port
-
- # bidirectional link
- forward = (local_node, local_port, None, remote_node)
-
- # scan for reverse
- remote_port = links_out.get((remote_node, local_node))
-
- if remote_port :
- reverse = (remote_node, remote_port, None, local_node)
-
- log.info("%s:%s <-> %s:%s", local_node, local_port, remote_port, remote_host)
-
- # fill in remote_port for bidirectional link
- del links[reverse]
- reverse = local_node, local_port, remote_port, remote_node
- links[reverse] = link_vlans
-
- else :
- log.info("%s:%s -> %s", local_node, local_port, remote_host)
-
- links[forward] = link_vlans
-
# second graph: manual ports
for host in hosts :
local_node = host
@@ -354,7 +301,12 @@
# XXX: copypasta
nodes[local_node] = host.location or str(host)
- for port, remote in host_links.iteritems() :
+ for link_port, remote in host_links.iteritems() :
+ if link_port.isdigit() :
+ port = int(link_port)
+ else :
+ port = str(link_port)
+
# map remote -> remote_host
if '@' in remote :
remote_location, remote_domain = remote.split('@', 1)
@@ -389,12 +341,15 @@
log.debug("%s:%s: confirm -> %s", host, port, remote_host)
links_out[(local_node, remote_node)] = port
+ nodes_port[(local_node, port)] = remote_node
+ nodes_out.setdefault(local_node, set()).add(remote_node)
# update directional or missing links
remote_port = links_out.get((remote_node, local_node))
reverse_port = links_in.get((local_node, remote_node))
if reverse_port and reverse_port != port :
+ # XXX: this can be caused by str vs int >_>
log.warn("%s:%s: reverse port mismatch %s <- %s", host, port, reverse_port, remote_node)
@@ -424,6 +379,82 @@
links[(local_node, local_port, None, remote_node)] = None
+ if options.graph_bridge :
+ # third graph: bridge
+ for host, host_attrs in snmp.iteritems() :
+ local_node = host
+
+ node_out = nodes_out.get(local_node)
+
+ if not node_out :
+ log.warning("%s: no outgoing links, skipping bridge", host)
+ continue
+
+ bridge = { }
+
+ for port, ethernets in host_attrs.get('bridge', { }).iteritems() :
+ bridge[(port, None)] = ethernets
+
+ for vlan, vlan_attrs in host_attrs.get('vlan', { }).iteritems() :
+ for port, ethernets in vlan_attrs.get('bridge', { }).iteritems() :
+ bridge[(port, vlan)] = ethernets
+
+ for (port, vlan), ethernets in bridge.iteritems() :
+ local_port = port
+
+ remote_node = nodes_port.get((local_node, local_port))
+
+ if remote_node :
+ log.debug("%s:%s/%s bridge skip -> %s", host, port, vlan, remote_node)
+ continue
+
+ for ethernet in ethernets :
+ # remote host
+ if ethernet in hosts_by_ethernet :
+ remote_node = remote_host = hosts_by_ethernet[ethernet]
+
+ remote_label = remote_host.location or str(remote_host)
+
+ log.debug("%s:%s/%s bridge %s = %s (%s)", host, port, vlan, ethernet, remote_host, remote_label)
+ else :
+ remote_node = remote_host = None
+
+ if not remote_host :
+ continue
+
+ if remote_node not in nodes :
+ log.debug("%s:%s: lazy-add remote %s (%s)", host, port, remote_node, remote_label)
+
+ nodes[remote_node] = remote_label
+
+ # unknown vlans
+ link_vlans = None
+
+ # directional link
+ links_out[(local_node, remote_node)] = local_port
+
+ # bidirectional link
+ forward = (local_node, local_port, None, remote_node)
+
+ # scan for reverse
+ remote_port = links_out.get((remote_node, local_node))
+
+ if remote_port :
+ reverse = (remote_node, remote_port, None, local_node)
+
+ log.info("%s:%s <-> %s:%s", local_node, local_port, remote_port, remote_host)
+
+ # fill in remote_port for bidirectional link
+ del links[reverse]
+ reverse = local_node, local_port, remote_port, remote_node
+ links[reverse] = link_vlans
+
+ else :
+ log.info("%s:%s -> %s", local_node, local_port, remote_host)
+
+ links[forward] = link_vlans
+
+
return nodes, links