poll_macs.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. #!/usr/bin/env python3
  2. #
  3. # Copyright (c) 2017-2019 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. CACHE_FILE = '/home/jclarke/mac_counts.dat'
  34. CACHE_FILE_TMP = CACHE_FILE + '.tmp'
  35. commands = [
  36. {
  37. 'command': 'show mac address-table count | inc Dynamic Address Count',
  38. 'pattern': r'Dynamic Address Count:\s+(\d+)',
  39. 'metric': 'totalMacs',
  40. 'devices': ['core1-l3c', 'core2-l3c']
  41. },
  42. {
  43. 'command': 'show mac address-table dynamic | inc Total',
  44. 'pattern': r'Total.*: (\d+)',
  45. 'metric': 'totalMacs',
  46. 'devicePatterns': [
  47. {
  48. 'pattern': '10.127.0.{}',
  49. 'range': {
  50. 'min': 1,
  51. 'max': 60
  52. }
  53. }
  54. ]
  55. },
  56. {
  57. 'command': 'show ip arp summary | inc IP ARP',
  58. 'pattern': r'(\d+) IP ARP entries',
  59. 'metric': 'arpEntries',
  60. 'devicePatterns': [
  61. {
  62. 'pattern': '10.127.0.{}',
  63. 'range': {
  64. 'min': 1,
  65. 'max': 60
  66. }
  67. }
  68. ]
  69. }
  70. ]
  71. def get_results(ssh_client, ip, command, pattern, metric):
  72. response = ''
  73. try:
  74. ssh_client.connect(ip, username=CLEUCreds.NET_USER, password=CLEUCreds.NET_PASS,
  75. timeout=5, allow_agent=False, look_for_keys=False)
  76. chan = ssh_client.invoke_shell()
  77. output = ''
  78. try:
  79. chan.sendall('term length 0\n')
  80. chan.sendall('term width 0\n')
  81. chan.sendall('{}\n'.format(command))
  82. j = 0
  83. while j < 10:
  84. if chan.recv_ready():
  85. break
  86. time.sleep(.5)
  87. j += 1
  88. while chan.recv_ready():
  89. output += chan.recv(65535)
  90. except Exception as ie:
  91. response = '{}{{idf="{}"}}'.format(metric, ip)
  92. sys.stderr.write(
  93. 'Failed to get MACs from {}: {}\n'.format(ip, ie))
  94. return response
  95. m = re.search(pattern, output)
  96. if m:
  97. response = '{}{{idf="{}"}} {}'.format(metric, ip, m.group(1))
  98. else:
  99. response = '{}{{idf="{}"}} 0'.format(metric, ip)
  100. except Exception as e:
  101. ssh_client.close()
  102. sys.stderr.write('Failed to connect to {}: {}\n'.format(ip, e))
  103. return ''
  104. ssh_client.close()
  105. return response
  106. def get_metrics():
  107. response = []
  108. ssh_client = paramiko.SSHClient()
  109. ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
  110. for command in commands:
  111. if 'devices' in command:
  112. for device in command['devices']:
  113. response.append(get_results(ssh_client, device, command['command'], command['pattern'], command['metric']))
  114. else:
  115. for pattern in command['devicePatterns']:
  116. if 'range' in pattern:
  117. for i in range(pattern['range']['min'], pattern['range']['max']):
  118. response.append(get_results(ssh_client, pattern['pattern'].format(str(i)), command[
  119. 'command'], command['pattern'], command['metric']))
  120. else:
  121. for sub in pattern['subs']:
  122. response.append(get_results(ssh_client, pattern['pattern'].format(sub), command[
  123. 'command'], command['pattern'], command['metric']))
  124. return response
  125. if __name__ == '__main__':
  126. response=get_metrics()
  127. fd=open(CACHE_FILE_TMP, 'w')
  128. json.dump(response, fd, indent=4)
  129. fd.close()
  130. os.rename(CACHE_FILE_TMP, CACHE_FILE)