poll_macs.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. #!/usr/bin/env python2
  2. #
  3. # Copyright (c) 2017-2018 Joe Clarke <jclarke@cisco.com>
  4. # All rights reserved.
  5. #
  6. # Redistribution and use in source and binary forms, with or without
  7. # modification, are permitted provided that the following conditions
  8. # are met:
  9. # 1. Redistributions of source code must retain the above copyright
  10. # notice, this list of conditions and the following disclaimer.
  11. # 2. Redistributions in binary form must reproduce the above copyright
  12. # notice, this list of conditions and the following disclaimer in the
  13. # documentation and/or other materials provided with the distribution.
  14. #
  15. # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  16. # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  19. # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  21. # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  22. # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  23. # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  24. # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  25. # SUCH DAMAGE.
  26. import os
  27. import re
  28. import sys
  29. import time
  30. import json
  31. import paramiko
  32. import CLEUCreds
  33. IDF_COUNT = 60
  34. IDF_PATTERN = '10.127.0.{}'
  35. CACHE_FILE = '/home/jclarke/mac_counts.dat'
  36. CACHE_FILE_TMP = CACHE_FILE + '.tmp'
  37. commands = [
  38. {
  39. 'command': 'show mac address-table count | inc Dynamic Address Count',
  40. 'pattern': r'Dynamic Address Count:\s+(\d+)',
  41. 'metric': 'totalMacs',
  42. 'devices': ['core1-l3c', 'core2-l3c']
  43. },
  44. {
  45. 'command': 'show mac address-table dynamic | inc Total',
  46. 'pattern': r'Total.*: (\d+)',
  47. 'metric': 'totalMacs',
  48. 'devicePatterns': [
  49. {
  50. 'pattern': '10.127.0.{}',
  51. 'range': {
  52. 'min': 1,
  53. 'max': 60
  54. }
  55. }
  56. ]
  57. },
  58. {
  59. 'command': 'show ip arp summary | inc IP ARP',
  60. 'pattern': r'(\d+) IP ARP entries',
  61. 'metric': 'arpEntries',
  62. 'devicePatterns': [
  63. {
  64. 'pattern': '10.127.0.{}',
  65. 'range': {
  66. 'min': 1,
  67. 'max': 60
  68. }
  69. }
  70. ]
  71. }
  72. ]
  73. def get_results(ssh_client, ip, command, pattern, metric):
  74. response = ''
  75. try:
  76. ssh_client.connect(ip, username=CLEUCreds.NET_USER, password=CLEUCreds.NET_PASS,
  77. timeout=5, allow_agent=False, look_for_keys=False)
  78. chan = ssh_client.invoke_shell()
  79. output = ''
  80. try:
  81. chan.sendall('term length 0\n')
  82. chan.sendall('term width 0\n')
  83. chan.sendall('{}\n'.format(command))
  84. j = 0
  85. while j < 10:
  86. if chan.recv_ready():
  87. break
  88. time.sleep(.5)
  89. j += 1
  90. while chan.recv_ready():
  91. output += chan.recv(65535)
  92. except Exception as ie:
  93. response = '{}{{idf="{}"}}'.format(metric, ip)
  94. sys.stderr.write(
  95. 'Failed to get MACs from {}: {}\n'.format(ip, ie))
  96. return response
  97. m = re.search(pattern, output)
  98. if m:
  99. response = '{}{{idf="{}"}} {}'.format(metric, ip, m.group(1))
  100. else:
  101. response = '{}{{idf="{}"}} 0'.format(metric, ip)
  102. except Exception as e:
  103. ssh_client.close()
  104. sys.stderr.write('Failed to connect to {}: {}\n'.format(ip, e))
  105. return ''
  106. ssh_client.close()
  107. return response
  108. def get_metrics():
  109. response = []
  110. ssh_client = paramiko.SSHClient()
  111. ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
  112. for command in commands:
  113. if 'devices' in command:
  114. for device in command['devices']:
  115. response.append(get_results(ssh_client, device, command['command'], command['pattern'], command['metric']))
  116. else:
  117. for pattern in command['devicePatterns']:
  118. if 'range' in pattern:
  119. for i in range(pattern['range']['min'], pattern['range']['max']):
  120. response.append(get_results(ssh_client, pattern['pattern'].format(str(i)), command[
  121. 'command'], command['pattern'], command['metric']))
  122. else:
  123. for sub in pattern['subs']:
  124. response.append(get_results(ssh_client, pattern['pattern'].format(sub), command[
  125. 'command'], command['pattern'], command['metric']))
  126. return response
  127. if __name__ == '__main__':
  128. response=get_metrics()
  129. fd=open(CACHE_FILE_TMP, 'w')
  130. json.dump(response, fd, indent=4)
  131. fd.close()
  132. os.rename(CACHE_FILE_TMP, CACHE_FILE)