__init__.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. from copy import deepcopy
  2. import json
  3. import logging
  4. import time
  5. import urllib2
  6. from .alfred import AlfredParser
  7. from .batman import BatmanParser
  8. from .dashing import DashingClient
  9. from .graphite import GraphitePush
  10. from .server import ApiServer
  11. from .storage import Storage
  12. __all__ = [
  13. 'AlfredParser', 'BatmanParser',
  14. 'DashingClient', 'GraphitePush',
  15. 'Storage', 'ApiServer',
  16. 'dict_merge', 'merge_alfred_batman',
  17. 'resolve_ipblock', 'mac2id',
  18. ]
  19. logger = logging.getLogger('ffstatus')
  20. def mac2id(mac):
  21. return mac.lower().replace(':', '')
  22. def dict_merge(a, b):
  23. '''recursively merges dict's. not just simple a['key'] = b['key'], if
  24. both a and bhave a key who's value is a dict then dict_merge is called
  25. on both values and the result stored in the returned dictionary.'''
  26. if not isinstance(b, dict):
  27. return b
  28. result = deepcopy(a)
  29. for k, v in b.iteritems():
  30. if k in result and isinstance(result[k], dict):
  31. result[k] = dict_merge(result[k], v)
  32. elif k in result and isinstance(result[k], list):
  33. result[k] = result[k] + [ deepcopy(x) for x in v if x not in result[k] ]
  34. else:
  35. result[k] = deepcopy(v)
  36. return result
  37. def merge_alfred_batman(alfreddata, batmandata):
  38. merged = {}
  39. batlookup = {}
  40. for nodeid in batmandata:
  41. batlookup[nodeid] = nodeid
  42. for bda in batmandata[nodeid]['aliases']:
  43. batlookup[bda] = nodeid
  44. for nodeid in alfreddata:
  45. nodeinfo = alfreddata[nodeid]
  46. candidates = set()
  47. candidates.add(nodeid)
  48. if 'mac' in nodeinfo: candidates.add(mac2id(nodeinfo['mac']))
  49. if 'macs' in nodeinfo:
  50. for mac in nodeinfo['macs']:
  51. candidates.add(mac2id(mac))
  52. if 'network' in nodeinfo:
  53. n = nodeinfo['network']
  54. if 'mac' in n: candidates.add(mac2id(n['mac']))
  55. if 'mesh_interfaces' in n:
  56. for mac in n['mesh_interfaces']:
  57. candidates.add(mac2id(mac))
  58. if not 'neighbours' in nodeinfo: nodeinfo['neighbours'] = []
  59. for candidate_raw in candidates:
  60. candidate = batlookup[candidate_raw] if candidate_raw in batlookup else candidate_raw
  61. if candidate in batmandata:
  62. nodeinfo = dict_merge(nodeinfo, batmandata[candidate])
  63. merged[nodeid] = nodeinfo
  64. return merged
  65. no_ipblock_resolves_until = None
  66. def resolve_ipblock(ipaddr):
  67. """Resolve the given IP address to its inetnum entry at RIPE."""
  68. global no_ipblock_resolves_until
  69. if not no_ipblock_resolves_until is None:
  70. if no_ipblock_resolves_until < time.time():
  71. no_ipblock_resolves_until = None
  72. else:
  73. logger.info('IP-Block-Resolving suspended for {0} seconds. Won\'t resolve \'{1}\' now.'.format(int(no_ipblock_resolves_until-time.time()), ipaddr))
  74. return None
  75. url = 'http://rest.db.ripe.net/search.json?query-string=' + str(ipaddr)
  76. try:
  77. response = json.load(urllib2.urlopen(url))
  78. assert isinstance(response, dict)
  79. obj = [x for x in response['objects']['object'] if x['type'] in ['inetnum','inet6num']][0]
  80. attrib = obj['attributes']['attribute']
  81. netname = '\n'.join([x['value'] for x in attrib if x['name'] == 'netname'])
  82. netblock = '\n'.join([x['value'] for x in attrib if x['name'] in ['inetnum','inet6num']])
  83. desc = '\n'.join([x['value'] for x in attrib if x['name'] == 'descr'])
  84. return {
  85. 'name': netname,
  86. 'block': netblock,
  87. 'description': desc,
  88. }
  89. except urllib2.URLError as err:
  90. output = err.read()
  91. logger.error('Error "{1}" querying ip \'{0}\' from RIPE API: {2}'.format(ipaddr, err, output))
  92. if 'Retry-After' in err.headers:
  93. retry = int(err.headers['Retry-After'])
  94. logger.warn('I won\'t resolve IPs for {0} seconds as requested by RIPE API (header=\'{1}\').'.format(retry, err.header['Retry-After']))
  95. no_ipblock_resolves_until = time.time() + int(err.headers['Retry-After'])
  96. else:
  97. logger.warn('I won\'t resolve IPs for the next hour (API didn\'t give better hint).')
  98. no_ipblock_resolves_until = time.time() + 3600