poll_dnac_issues.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  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. import os
  27. import re
  28. import sys
  29. import time
  30. import json
  31. import string
  32. import random
  33. import requests
  34. from requests.packages.urllib3.exceptions import InsecureRequestWarning
  35. requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
  36. import CLEUCreds
  37. from sparker import Sparker, MessageType
  38. from cleu.config import Config as C
  39. ROOM = "DNA Alarms"
  40. CACHE_FILE = "/home/jclarke/dna_issues.json"
  41. def get_identity_token():
  42. url = C.SDA_BASE + "/api/system/v1/identitymgmt/login"
  43. try:
  44. response = requests.request("GET", url, headers={"Authorization": CLEUCreds.JCLARKE_BASIC}, verify=False)
  45. response.raise_for_status()
  46. except Exception as e:
  47. print("ERROR: Failed to login to DNAC: {}".format(getattr(e, "message", repr(e))))
  48. return None
  49. jwt = response.headers.get("Set-Cookie")
  50. if jwt:
  51. m = re.search(r"X-JWT-ACCESS-TOKEN=([^;]+)", jwt)
  52. if m:
  53. return m.group(1)
  54. return None
  55. def main():
  56. global ROOM, CACHE_FILE
  57. jwt = get_identity_token()
  58. if not jwt:
  59. print("No cookies")
  60. sys.exit(1)
  61. prev_state = {}
  62. cookies = {
  63. "X-JWT-ACCESS-TOKEN": jwt,
  64. "JSESSIONID": ("".join(random.choice(string.ascii_lowercase) for i in range(16))),
  65. "cisco-dna-core-shell-actionItemModal": "false",
  66. }
  67. try:
  68. with open(CACHE_FILE) as fd:
  69. prev_state = json.load(fd)
  70. except Exception as e:
  71. pass
  72. end_time = int(time.time() * 1000)
  73. if "start_time" not in prev_state:
  74. start_time = end_time - 86400000
  75. else:
  76. start_time = prev_state["start_time"]
  77. spark = Sparker(token=CLEUCreds.SPARK_TOKEN)
  78. url = C.SDA_BASE + "/api/assurance/v1/issue/global-category?startTime={}&endTime={}&limit=10".format(start_time, end_time)
  79. payload = {"sortBy": {"priority": "ASC"}, "issueStatus": "active", "filters": {}}
  80. i = 0
  81. seen_groups = {}
  82. seen_issues = {}
  83. while True:
  84. try:
  85. response = requests.request(
  86. "POST",
  87. url + "&page={}".format(i),
  88. cookies=cookies,
  89. json=payload,
  90. headers={"content-type": "application/json", "accept": "application/json"},
  91. verify=False,
  92. )
  93. response.raise_for_status()
  94. except Exception as e:
  95. print("ERROR: Failed to get issue list from DNAC: {}".format(getattr(e, "message", repr(e))))
  96. break
  97. j = response.json()
  98. if "response" in j:
  99. for issue in j["response"]:
  100. if issue["groupName"] in seen_groups:
  101. continue
  102. seen_groups[issue["groupName"]] = True
  103. iurl = C.SDA_BASE + "/api/assurance/v1/issue/category-detail?startTime={}&endTime={}&limit=25&page=0".format(
  104. start_time, end_time
  105. )
  106. ipayload = {"groupName": issue["groupName"], "filters": {}, "issueStatus": "active"}
  107. try:
  108. response = requests.request(
  109. "POST",
  110. iurl,
  111. json=ipayload,
  112. cookies=cookies,
  113. headers={"content-type": "application/json", "accept": "application/json"},
  114. verify=False,
  115. )
  116. response.raise_for_status()
  117. except Exception as e:
  118. print("ERROR: Failed to fetch issue details for group {}: {}".format(j["groupName"], getattr(e, "message", repr(e))))
  119. break
  120. details = response.json()
  121. for det in details["response"]:
  122. seen_issues[det["issueId"]] = det["issueMessage"]
  123. mt = MessageType.WARNING
  124. if det["priority"] == "P1":
  125. mt = MessageType.BAD
  126. spark.post_to_spark(C.WEBEX_TEAM, ROOM, det["issueMessage"], mt)
  127. if not j["pagination"]["next"]:
  128. break
  129. i += 1
  130. if "issues" in prev_state:
  131. for issue in prev_state["issues"]:
  132. if issue not in seen_issues:
  133. spark.post_to_spark(C.WEBEX_TEAM, ROOM, prev_state["issues"][issue], MessageType.GOOD)
  134. prev_state["start_time"] = end_time
  135. prev_state["groups"] = seen_issues
  136. with open(CACHE_FILE, "w") as fd:
  137. json.dump(prev_state, fd, indent=4)
  138. if __name__ == "__main__":
  139. main()