get-devs.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. #!/usr/bin/env python3
  2. #
  3. # Copyright (c) 2017-2020 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. from builtins import range
  27. import requests
  28. from requests.packages.urllib3.exceptions import InsecureRequestWarning
  29. requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
  30. import json
  31. import sys
  32. import time
  33. import os
  34. from subprocess import call
  35. from sparker import Sparker, MessageType
  36. import pprint
  37. import re
  38. from multiprocessing import Pool
  39. import socket
  40. import CLEUCreds
  41. from cleu.config import Config as C
  42. CACHE_FILE = "/home/jclarke/cached_devs.dat"
  43. PING_DEVS_FILE = "/home/jclarke/ping-devs.json"
  44. MESSAGES = {
  45. "BAD": {"msg": "Pinger detected that device %s (IP: %s)%s is no longer reachable", "type": MessageType.BAD},
  46. "GOOD": {"msg": "Pinger has detected that device %s (IP: %s)%s is now reachable again", "type": MessageType.GOOD},
  47. }
  48. ROOM_NAME = "Device Alarms"
  49. excluded_devices = [r"^VHS-"]
  50. additional_devices = []
  51. def check_prev(dev_dic, prev_devs, pstate="REACHABLE"):
  52. send_msg = False
  53. for pd in prev_devs:
  54. if pd["name"] == dev_dic["name"]:
  55. if pd["reachability"] != pstate:
  56. send_msg = True
  57. break
  58. return send_msg
  59. def know_device(dev_dic, prev_devs):
  60. for pd in prev_devs:
  61. if pd["name"] == dev_dic["name"]:
  62. return True
  63. return False
  64. def ping_device(dev):
  65. global ROOM_NAME, MESSAGES, prev_devs, spark, excluded_devices
  66. dev_dic = {}
  67. dev_dic["name"] = dev["Hostname"]
  68. dev_dic["ip"] = dev["IPAddress"]
  69. if dev_dic["ip"] == "0.0.0.0":
  70. return None
  71. for exc in excluded_devices:
  72. if re.search(exc, dev_dic["name"]) or re.search(exc, dev_dic["ip"]):
  73. return None
  74. # print('Pinging {}'.format(dev_dic['name']))
  75. msg_tag = "BAD"
  76. send_msg = True
  77. if not dev["Reachable"]:
  78. send_msg = know_device(dev_dic, prev_devs)
  79. for i in range(2):
  80. res = call(["/usr/local/sbin/fping", "-q", "-r0", dev_dic["ip"]])
  81. time.sleep(0.5)
  82. if res != 0:
  83. dev_dic["reachability"] = "UNREACHABLE"
  84. send_msg = check_prev(dev_dic, prev_devs, "UNREACHABLE")
  85. else:
  86. dev_dic["reachability"] = "REACHABLE"
  87. msg_tag = "GOOD"
  88. send_msg = check_prev(dev_dic, prev_devs)
  89. if send_msg:
  90. loc = ""
  91. if "LocationDetail" in dev:
  92. loc = " (Location: {})".format(dev["LocationDetail"])
  93. message = MESSAGES[msg_tag]["msg"] % (dev_dic["name"], dev_dic["ip"], loc)
  94. spark.post_to_spark(C.WEBEX_TEAM, ROOM_NAME, message, MESSAGES[msg_tag]["type"])
  95. return dev_dic
  96. def get_devs(p):
  97. global additional_devices
  98. url = "http://{}/get/switches/json".format(C.TOOL)
  99. devices = []
  100. # response = requests.request('GET', url)
  101. code = 200
  102. # code = response.status_code
  103. if code == 200:
  104. # j = json.loads(response.text)
  105. j = []
  106. for dev in additional_devices:
  107. ip = dev
  108. try:
  109. ip = socket.gethostbyname(dev)
  110. except Exception as e:
  111. spark.post_to_spark(C.WEBEX_TEAM, ROOM_NAME, "Failed to resolve {}: {}".format(dev, e), MessageType.WARNING)
  112. continue
  113. j.append({"Hostname": dev, "IPAddress": ip, "Reachable": True})
  114. results = [pool.apply_async(ping_device, [d]) for d in j]
  115. for res in results:
  116. retval = res.get()
  117. if retval is not None:
  118. devices.append(retval)
  119. return devices
  120. if __name__ == "__main__":
  121. prev_devs = []
  122. if os.path.exists(CACHE_FILE):
  123. fd = open(CACHE_FILE, "r")
  124. prev_devs = json.load(fd)
  125. fd.close()
  126. spark = Sparker(token=CLEUCreds.SPARK_TOKEN)
  127. try:
  128. fd = open(PING_DEVS_FILE, "r")
  129. additional_devices = json.load(fd)
  130. fd.close()
  131. except:
  132. pass
  133. pool = Pool(20)
  134. devs = get_devs(pool)
  135. fd = open(CACHE_FILE, "w")
  136. json.dump(devs, fd, ensure_ascii=False, indent=4)
  137. fd.close()