batman.py 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. #!/usr/bin/python
  2. from __future__ import print_function
  3. import io
  4. import json
  5. import string
  6. import subprocess
  7. import time
  8. class BatmanParser:
  9. batadv_vis = 'batadv-vis'
  10. mactranslation = string.maketrans('2367abef', '014589cd')
  11. def __str__(self):
  12. return 'BatmanParser \'{0}\''.format(self.batadv_vis)
  13. def sanitycheck(self):
  14. """Checks that batadv-vis is executable and gives sane output."""
  15. testdata = None
  16. try:
  17. testdata = subprocess.check_output([self.batadv_vis, '-f', 'jsondoc'])
  18. except Exception as err:
  19. raise Exception("batadv-vis not found or incompatible: " + str(err))
  20. try:
  21. json.loads(testdata)
  22. except Exception as err:
  23. raise Exception("batadv-vis does not return valid JSON data: " + str(err))
  24. return True
  25. def mac2id(self, mac):
  26. """Derives a nodeid from the given MAC address."""
  27. temp = str(mac.lower().replace(':', ''))
  28. # temp = temp[0] + temp[1].translate(self.mactranslation) + temp[2:]
  29. return temp
  30. def fetch(self, batadv_dump=None, include_rawdata=False):
  31. """Fetches the current data from batadv-vis and returns it."""
  32. data = { }
  33. ts = int(time.time())
  34. # call batadv-vis and parse output as JSON
  35. rawdata = subprocess.check_output([self.batadv_vis, '-f', 'jsondoc'])
  36. batmandata = json.loads(rawdata)
  37. # dump raw data into file if requested
  38. if not batadv_dump is None:
  39. f = io.open(batadv_dump, 'w')
  40. f.write(rawdata)
  41. f.close()
  42. # parse raw data, convert all MAC into nodeid
  43. for item in batmandata['vis']:
  44. itemid = self.mac2id(item['primary'])
  45. aliases = []
  46. if 'secondary' in item:
  47. for mac in item['secondary']:
  48. aliases.append(self.mac2id(mac))
  49. neighbours = {}
  50. if 'neighbors' in item:
  51. for neighbour in item['neighbors']:
  52. #if neighbour['router'] != item['primary']:
  53. # print('node {0}\'s neighbor {1} has unexpected router {2}'.format(itemid, neighbour['neighbor'], neighbour['router']))
  54. neighbours[neighbour['neighbor']] = float(neighbour['metric'])
  55. # construct dict entry as expected by BATCAVE
  56. data[itemid] = {
  57. 'aliases': aliases,
  58. 'neighbours': neighbours,
  59. 'clients': [ x for x in item['clients'] ] if 'clients' in item else [],
  60. '__UPDATED__': { 'batadv': ts, },
  61. '__RAW__': { 'batadv': { itemid: item, } },
  62. }
  63. return data
  64. # standalone test mode
  65. if __name__ == "__main__":
  66. b = BatmanParser()
  67. try:
  68. b.sanitycheck()
  69. except Exception as err:
  70. print('SANITY-CHECK failed:', str(err))
  71. import sys
  72. sys.exit(1)
  73. data = b.fetch()
  74. print(json.dumps(data))