6 """ |
6 """ |
7 |
7 |
8 import pvl.args |
8 import pvl.args |
9 import pvl.hosts |
9 import pvl.hosts |
10 from pvl.invoke import merge |
10 from pvl.invoke import merge |
11 from pvl.snmp import snmp, lldp, vlan |
11 from pvl.snmp import snmp, lldp, vlan, bridge |
12 |
12 |
13 import logging; log = logging.getLogger('pvl.hosts-lldp') |
13 import logging; log = logging.getLogger('pvl.hosts-lldp') |
14 import optparse |
14 import optparse |
15 |
15 |
16 def hosts_snmp (options, hosts) : |
16 def hosts_snmp (options, hosts) : |
76 continue |
76 continue |
77 |
77 |
78 log.info("%s: %s", host, count) |
78 log.info("%s: %s", host, count) |
79 |
79 |
80 yield host, agent |
80 yield host, agent |
|
81 |
|
82 def hosts_bridge (options, hosts) : |
|
83 """ |
|
84 Discover Bridge-supporting hosts. |
|
85 |
|
86 Yields Host, BridgeAgent |
|
87 """ |
|
88 |
|
89 for host, host_snmp in hosts_snmp(options, hosts) : |
|
90 agent = bridge.BridgeAgent.apply(options, host.fqdn(), community=host_snmp.get('community')) |
|
91 |
|
92 try : |
|
93 agent.ping() |
|
94 except snmp.SNMPError as ex : |
|
95 log.warning("%s: %s", host, ex) |
|
96 continue |
|
97 |
|
98 log.info("%s", host) |
|
99 |
|
100 yield host, agent |
|
101 |
81 |
102 |
82 def apply_hosts_lldp (options, hosts) : |
103 def apply_hosts_lldp (options, hosts) : |
83 """ |
104 """ |
84 Query host LLDP info. |
105 Query host LLDP info. |
85 """ |
106 """ |
109 import collections |
130 import collections |
110 |
131 |
111 def apply_hosts_vlan (options, hosts) : |
132 def apply_hosts_vlan (options, hosts) : |
112 """ |
133 """ |
113 Query host VLAN ports. |
134 Query host VLAN ports. |
|
135 |
|
136 Yields host, { port: (untagged, [tagged]) } |
114 """ |
137 """ |
115 |
138 |
116 _hosts_vlan = list(hosts_vlan(options, hosts)) |
139 _hosts_vlan = list(hosts_vlan(options, hosts)) |
117 |
140 |
118 for host, agent in _hosts_vlan : |
141 for host, agent in _hosts_vlan : |
138 yield host, dict( |
161 yield host, dict( |
139 ( |
162 ( |
140 port, (vlan_untagged.get(port), tuple(vlan_tagged[port])) |
163 port, (vlan_untagged.get(port), tuple(vlan_tagged[port])) |
141 ) for port in set(vlan_untagged) | set(vlan_tagged) |
164 ) for port in set(vlan_untagged) | set(vlan_tagged) |
142 ) |
165 ) |
|
166 |
|
167 def apply_hosts_bridge (options, hosts) : |
|
168 """ |
|
169 Query host bridge tables. |
|
170 |
|
171 Yields host, { port: (macs) } |
|
172 """ |
|
173 |
|
174 for host, agent in hosts_bridge(options, hosts) : |
|
175 ports = collections.defaultdict(list) |
|
176 |
|
177 for ether, port in agent.fdb() : |
|
178 if port : |
|
179 ports[port].append(ether) |
|
180 |
|
181 yield host, ports |
143 |
182 |
144 COLOR_VLANS = { |
183 COLOR_VLANS = { |
145 1: 'grey', # pvl-lan |
184 1: 'grey', # pvl-lan |
146 2: 'blue', # pvl-lan2 |
185 2: 'blue', # pvl-lan2 |
147 3: 'red', # pvl-san |
186 3: 'red', # pvl-san |
342 vlans = dict(apply_hosts_vlan(options, hosts)) |
381 vlans = dict(apply_hosts_vlan(options, hosts)) |
343 |
382 |
344 # discover node/port graph |
383 # discover node/port graph |
345 items = apply_hosts_lldp(options, hosts) |
384 items = apply_hosts_lldp(options, hosts) |
346 |
385 |
|
386 # discover edge nodes |
|
387 leafs = apply_hosts_bridge(options, hosts) |
|
388 |
347 # print |
389 # print |
348 if options.graph_dot : |
390 if options.graph_dot : |
349 apply_graph(options, items, vlans) |
391 apply_graph(options, items, vlans) |
350 else : |
392 else : |
351 for host, local, remote, remote_host in items : |
393 for host, local, remote, remote_host in items : |
352 if remote_host : |
394 if remote_host : |
353 print "{host:30} {host.location:>30} {local[port]:>25} <-> {remote[port]:<25} {remote_host.location:>30} # {remote[chassis]} ({remote_host})".format(host=host, local=local, remote=remote, remote_host=remote_host) |
395 print "{host:30} {host.location:>30} {local[port]:>25} <-> {remote[port]:<25} {remote_host.location:>30} # {remote[chassis]} ({remote_host})".format(host=host, local=local, remote=remote, remote_host=remote_host) |
354 else : |
396 else : |
355 print "{host:30} {host.location:>30} {local[port]:>25} <-- {remote[port]:<25} {empty:30} # {remote[chassis]} ({remote[sys_name]})".format(host=host, local=local, remote=remote, empty='') |
397 print "{host:30} {host.location:>30} {local[port]:>25} <-- {remote[port]:<25} {empty:30} # {remote[chassis]} ({remote[sys_name]})".format(host=host, local=local, remote=remote, empty='') |
356 |
398 |
357 |
399 for host, ports in leafs : |
|
400 for port, ethers in ports.iteritems() : |
|
401 print "{host:30} {host.location:>30} {port:25} <== # {ethers}".format(host=host, port=port, ethers=' '.join(ethers)) |
358 |
402 |
359 if __name__ == '__main__': |
403 if __name__ == '__main__': |
360 pvl.args.main(main) |
404 pvl.args.main(main) |