184 src_label = '"{host.location}"'.format(host=host) |
184 src_label = '"{host.location}"'.format(host=host) |
185 |
185 |
186 if src_name in nodes : |
186 if src_name in nodes : |
187 src = nodes[src_name] |
187 src = nodes[src_name] |
188 else : |
188 else : |
189 src = nodes[src_name] = pydot.Node(src_name, label=src_label) |
189 src = nodes[src_name] = pydot.Node(src_name, |
|
190 label = src_label, |
|
191 fontsize = 18, |
|
192 ) |
190 dot.add_node(src) |
193 dot.add_node(src) |
191 |
194 |
192 # dst |
195 # dst |
193 if remote_host : |
196 if remote_host : |
194 dst_name = str(remote_host) |
197 dst_name = str(remote_host) |
203 dst_label = '"{remote[chassis]}"'.format(remote=remote) |
206 dst_label = '"{remote[chassis]}"'.format(remote=remote) |
204 |
207 |
205 if dst_name in nodes : |
208 if dst_name in nodes : |
206 dst = nodes[dst_name] |
209 dst = nodes[dst_name] |
207 else : |
210 else : |
208 dst = nodes[dst_name] = pydot.Node(dst_name, label=dst_label) |
211 dst = nodes[dst_name] = pydot.Node(dst_name, |
|
212 label = dst_label, |
|
213 fontsize = 18, |
|
214 ) |
209 dot.add_node(dst) |
215 dot.add_node(dst) |
210 |
216 |
211 # edges |
217 # edges |
212 headlabel = '"{remote[port]}"'.format(remote=remote) |
218 headlabel = '"{remote[port]}"'.format(remote=remote) |
213 taillabel = '"{local[port]}"'.format(local=local) |
219 taillabel = '"{local[port]}"'.format(local=local) |
214 fillcolor = None |
220 fillcolor = 'black' |
215 color = None |
221 color = 'black' |
|
222 untag = tagged = None |
216 |
223 |
217 # vlans? |
224 # vlans? |
218 if host in vlans and local['port_id'] in vlans[host] : |
225 if vlans and host in vlans and local['port_id'] in vlans[host] : |
219 untag, tagged = vlans[host][local['port_id']] |
226 untag, tagged = vlans[host][local['port_id']] |
220 |
227 |
221 log.debug("%s#%s: %s+%s", host, local['port_id'], untag, tagged) |
228 log.debug("%s#%s: %s+%s", host, local['port_id'], untag, tagged) |
222 |
229 |
223 colors = [] |
230 colors = [] |
246 log.warn("%s#%s: chosing new vlan %s color %s", host, local['port_id'], untag, color) |
253 log.warn("%s#%s: chosing new vlan %s color %s", host, local['port_id'], untag, color) |
247 |
254 |
248 fillcolor = vlan_colors[tag] = color |
255 fillcolor = vlan_colors[tag] = color |
249 |
256 |
250 # first color overrides fillcolor for heads |
257 # first color overrides fillcolor for heads |
251 if colors and fillcolor : |
258 if colors and untag : |
252 color = ':'.join([fillcolor] + colors) |
259 color = ':'.join([fillcolor] + colors) |
253 elif colors : |
260 elif colors : |
254 color = ':'.join(colors) |
261 color = ':'.join(colors) |
255 elif fillcolor : |
262 elif fillcolor : |
256 color = fillcolor |
263 color = fillcolor |
257 else : |
|
258 color = 'black' |
|
259 |
|
260 if not fillcolor : |
|
261 fillcolor = 'black' |
|
262 |
264 |
263 elif vlans : |
265 elif vlans : |
264 # XXX: this happens when LLDP gives us the LACP ports but the VLANS are on the TRK port |
266 # XXX: this happens when LLDP gives us the LACP ports but the VLANS are on the TRK port |
265 log.warn("%s#%s: unknown port for vlans: %s", host, local['port_id'], vlans.get(host)) |
267 log.warn("%s#%s: unknown port for vlans: %s", host, local['port_id'], vlans.get(host)) |
266 |
|
267 untag = tag = None |
|
268 |
|
269 else : |
|
270 untag = tag = None |
|
271 |
268 |
272 # edge |
269 # edge |
273 if (src_name, local['port'], dst_name, remote['port']) in edges : |
270 if (src_name, local['port'], dst_name, remote['port']) in edges : |
274 log.warning("%s:%s <- %s:%s: duplicate", src_name, local['port'], dst_name, remote['port']) |
271 log.warning("%s:%s <- %s:%s: duplicate", src_name, local['port'], dst_name, remote['port']) |
275 |
272 |
284 log.warn("%s -> %s: remote port mismatch: %s vs %s", src_name, dst_name, remote['port'], edge.get('taillabel')) |
281 log.warn("%s -> %s: remote port mismatch: %s vs %s", src_name, dst_name, remote['port'], edge.get('taillabel')) |
285 |
282 |
286 if edge.get('fillcolor') != fillcolor : |
283 if edge.get('fillcolor') != fillcolor : |
287 log.warn("%s#%s -> %s#%s: remote untag mismatch: %s vs %s", src_name, local['port'], dst_name, remote['port'], fillcolor, edge.get('fillcolor')) |
284 log.warn("%s#%s -> %s#%s: remote untag mismatch: %s vs %s", src_name, local['port'], dst_name, remote['port'], fillcolor, edge.get('fillcolor')) |
288 |
285 |
289 if edge.get('color') != '"' + (color or 'black') + '"' : |
286 if edge.get('color') != '"' + color + '"' : |
290 log.warn("%s#%s -> %s#%s: remote tagged mismatch: %s vs %s", src_name, local['port'], dst_name, remote['port'], color, edge.get('color')) |
287 log.warn("%s#%s -> %s#%s: remote tagged mismatch: %s vs %s", src_name, local['port'], dst_name, remote['port'], color, edge.get('color')) |
291 |
288 |
292 # mark as bidirectional |
289 # mark as bidirectional |
293 edges[(src_name, local['port'], dst_name, remote['port'])] = edge |
290 edges[(src_name, local['port'], dst_name, remote['port'])] = edge |
294 |
291 |
305 else : |
302 else : |
306 edge = edges[(src_name, local['port'], dst_name, remote['port'])] = pydot.Edge(src, dst, |
303 edge = edges[(src_name, local['port'], dst_name, remote['port'])] = pydot.Edge(src, dst, |
307 dir = 'forward' if untag else 'none', |
304 dir = 'forward' if untag else 'none', |
308 headlabel = headlabel, |
305 headlabel = headlabel, |
309 taillabel = taillabel, |
306 taillabel = taillabel, |
310 color = '"{color}"'.format(color=color) if color else 'black', |
307 color = '"{color}"'.format(color=color), |
311 fillcolor = fillcolor or 'black', |
308 fillcolor = fillcolor, |
312 ) |
309 ) |
313 |
310 |
314 dot.add_edge(edge) |
311 dot.add_edge(edge) |
315 |
312 |
316 if options.graph_dot : |
313 if options.graph_dot : |
327 parser.add_option_group(pvl.snmp.snmp.options(parser)) |
324 parser.add_option_group(pvl.snmp.snmp.options(parser)) |
328 |
325 |
329 parser.add_option('--graph-dot', |
326 parser.add_option('--graph-dot', |
330 help="Output .dot graph data") |
327 help="Output .dot graph data") |
331 |
328 |
|
329 parser.add_option('--no-vlans', action='store_const', dest='vlans', const=False, |
|
330 help="Do not color VLANs") |
|
331 |
332 # input |
332 # input |
333 options, args = parser.parse_args(argv[1:]) |
333 options, args = parser.parse_args(argv[1:]) |
334 pvl.args.apply(options) |
334 pvl.args.apply(options) |
335 |
335 |
336 hosts = pvl.hosts.apply(options, args) |
336 hosts = pvl.hosts.apply(options, args) |
337 |
337 |
338 # lookup host-port-vlan mappings |
338 # lookup host-port-vlan mappings |
339 vlans = dict(apply_hosts_vlan(options, hosts)) |
339 if options.vlans is False : |
|
340 vlans = None |
|
341 else : |
|
342 vlans = dict(apply_hosts_vlan(options, hosts)) |
340 |
343 |
341 # discover node/port graph |
344 # discover node/port graph |
342 items = apply_hosts_lldp(options, hosts) |
345 items = apply_hosts_lldp(options, hosts) |
343 |
346 |
344 # print |
347 # print |