143 lines
3.7 KiB
Python
143 lines
3.7 KiB
Python
#!/usr/bin/env python
|
|
""" Utility to scan a fedmsg setup for port availability.
|
|
|
|
Reports what percentage of fedmsg endpoints are bound and ready.
|
|
"""
|
|
|
|
import base64
|
|
import collections
|
|
import multiprocessing.pool
|
|
import socket
|
|
import sys
|
|
import time
|
|
|
|
import fedmsg.config
|
|
config = fedmsg.config.load_config()
|
|
|
|
timeout = 0.2
|
|
expected = '/wAAAAAAAAABfw=='
|
|
|
|
for_collectd = 'verbose' not in sys.argv
|
|
|
|
active = collections.defaultdict(list)
|
|
inactive = collections.defaultdict(list)
|
|
|
|
def info(content="\n"):
|
|
if not for_collectd:
|
|
sys.stdout.write(content)
|
|
sys.stdout.flush()
|
|
|
|
def scan_one(item):
|
|
name, endpoint = item
|
|
if not endpoint.startswith('tcp://'):
|
|
raise ValueError("Don't know how to deal with %r" % endpoint)
|
|
endpoint = endpoint[len('tcp://'):].split(':')
|
|
connection = None
|
|
try:
|
|
connection = socket.create_connection(endpoint, timeout)
|
|
actual = base64.b64encode(connection.recv(10))
|
|
if actual != expected:
|
|
inactive[name].append((
|
|
endpoint, "%r is not %r" % (actual, expected)))
|
|
info("F")
|
|
else:
|
|
active[name].append((endpoint, "all active"))
|
|
info(".")
|
|
except socket.error as e:
|
|
inactive[name].append((endpoint, str(e)))
|
|
info("F")
|
|
if connection:
|
|
connection.close()
|
|
|
|
|
|
def scan_all():
|
|
global active
|
|
global inactive
|
|
|
|
del active
|
|
del inactive
|
|
|
|
active = collections.defaultdict(list)
|
|
inactive = collections.defaultdict(list)
|
|
|
|
items = [(name, addr)
|
|
for name, endpoints in config['endpoints'].items()
|
|
for addr in endpoints]
|
|
|
|
# There is likely overhead in creating and destroying this thing, but we have
|
|
# memory leaks to track down.
|
|
pool = multiprocessing.pool.ThreadPool(25)
|
|
pool.map(scan_one, items)
|
|
pool.close()
|
|
|
|
info()
|
|
|
|
if 'verbose' in sys.argv:
|
|
import pprint
|
|
pprint.pprint(dict(active))
|
|
pprint.pprint(dict(inactive))
|
|
|
|
header = "".join([
|
|
"name".center(29),
|
|
"active".rjust(8),
|
|
"inactive".rjust(9),
|
|
"percent".rjust(9),
|
|
"reason".center(32),
|
|
])
|
|
info()
|
|
info(header + "\n")
|
|
info("-" * len(header) + "\n")
|
|
|
|
active_n_total, inactive_n_total = 0, 0
|
|
for name in sorted(config['endpoints']):
|
|
active_n = len(active[name])
|
|
inactive_n = len(inactive[name])
|
|
|
|
active_n_total += active_n
|
|
inactive_n_total += inactive_n
|
|
|
|
total = active_n + inactive_n
|
|
|
|
percent = ""
|
|
if total:
|
|
percent = "%%%0.1f" % (100 * float(active_n) / total)
|
|
|
|
reasons = set([reason for _, reason in inactive[name]])
|
|
|
|
info(name.rjust(29))
|
|
info(str(active_n).rjust(8))
|
|
info(str(inactive_n).rjust(9))
|
|
info(percent.rjust(9))
|
|
info(", ".join(reasons).rjust(32) + "\n")
|
|
|
|
info("-" * len(header) + "\n")
|
|
|
|
info(" total active: %i\n" % active_n_total)
|
|
info("total inactive: %i\n" % inactive_n_total)
|
|
value = 100 * float(active_n_total) / (active_n_total + inactive_n_total)
|
|
info("percent active: %%%0.1f\n" % value)
|
|
return value
|
|
|
|
if not for_collectd:
|
|
scan_all()
|
|
else:
|
|
interval = 5
|
|
host = socket.getfqdn()
|
|
while True:
|
|
start = time.time()
|
|
value = scan_all()
|
|
stop = timestamp = time.time()
|
|
delta = stop - start
|
|
output = (
|
|
"PUTVAL "
|
|
"{host}/fedmsg/percent "
|
|
"interval={interval} "
|
|
"{timestamp}:{value}"
|
|
).format(
|
|
host=host,
|
|
interval=interval,
|
|
timestamp=int(timestamp),
|
|
value="%0.1f" % value)
|
|
print(output)
|
|
if interval - delta > 0:
|
|
time.sleep(interval - delta)
|