Browse Source

Add a script to notify SDA messages to Teams.

Joe Clarke 4 years ago
parent
commit
0acc05f09c
2 changed files with 148 additions and 0 deletions
  1. 1 0
      automation/config/cleu/config.py
  2. 147 0
      automation/network/poll_dnac_issues.py

+ 1 - 0
automation/config/cleu/config.py

@@ -14,6 +14,7 @@ class Config:
     DHCP_SERVER = "dc1-dhcp." + DNS_DOMAIN
     PI = "cl-pi." + DNS_DOMAIN
     DNACS = ["cl-dnac04." + DNS_DOMAIN, "sdacleur20." + DNS_DOMAIN]
+    SDA_BASE = "https://sdacleur20." + DNS_DOMAIN
     CMX_GW = "http://cl-freebsd.{}:8002/api/v0.1/cmx".format(DNS_DOMAIN)
     CMX = "https://cl-cmx-1." + DNS_DOMAIN
     TOOL = "tool." + DNS_DOMAIN

+ 147 - 0
automation/network/poll_dnac_issues.py

@@ -0,0 +1,147 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2017-2020  Joe Clarke <jclarke@cisco.com>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+import os
+import re
+import sys
+import time
+import json
+import requests
+from requests.packages.urllib3.exceptions import InsecureRequestWarning
+
+requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
+
+import CLEUCreds
+from sparker import Sparker, MessageType
+from cleu.config import Config as C
+
+ROOM = "DNA Alarms"
+CACHE_FILE = "/home/jclarke/dna_issues.json"
+
+
+def get_identity_token():
+    url = C.SDA_BASE + "/api/system/v1/identitymgmt/login"
+
+    try:
+        response = requests.request("GET", url, cookies={"JSESSIONID": "foo"}, headers=CLEUCreds.DNAC_BASIC, verify=False)
+        response.raise_for_status()
+    except Exception as e:
+        print("ERROR: Failed to login to DNAC: {}".format(getattr(e, "message", repr(e))))
+        return None
+
+    return response.cookies
+
+
+def main():
+    cookies = get_identity_token()
+    if not cookies:
+        sys.exit(1)
+
+    prev_state = None
+
+    try:
+        with open(CACHE_FILE) as fd:
+            prev_state = json.load(fd)
+    except Exception as e:
+        print("ERROR: Failed to read cache file: {}".format(e))
+        sys.exit(1)
+
+    start_time = prev_state["start_time"]
+
+    spark = Sparker(token=CLEUCreds.SPARK_TOKEN)
+
+    end_time = int(time.time() * 1000)
+
+    url = C.SDA_BASE + "/api/assurance/v1/issues/global-category?startTime={}&endTime={}&limit=10".format(start_time, end_time)
+
+    payload = {"sortBy": {"priority": "ASC"}, "issueStatus": "active", "filters": {}}
+
+    i = 0
+    seen_groups = {}
+
+    while True:
+        url += "page={}".format(i)
+        try:
+            response = requests.request(
+                "POST",
+                url + "page={}".format(i),
+                cookies=cookies,
+                json=payload,
+                headers={"content-type": "application/json", "accept": "application/json"},
+                verify=False,
+            )
+            response.raise_for_status()
+        except Exception as e:
+            print("ERROR: Failed to get issue list from DNAC: {}".format(getattr(e, "message", repr(e))))
+            break
+
+        j = response.json()
+        if j["groupName"] in seen_groups:
+            continue
+
+        seen_groups[j["groupName"]] = True
+        if "response" in j:
+            for issue in j["response"]:
+                iurl = C.SDA_BASE + "/api/assurance/v1/issue/category-detail?startTime={}&endTime={}&limit=25&page=0"
+                ipayload = {"groupName": j["groupName"], "filters": {}, "issueStatus": "active"}
+
+                try:
+                    response = requests.request(
+                        "POST",
+                        iurl,
+                        json=ipayload,
+                        cookies=cookies,
+                        headers={"content-type": "application/json", "accept": "application/json"},
+                        verify=False,
+                    )
+                    response.raise_for_status()
+                except Exception as e:
+                    print("ERROR: Failed to fetch issue details for group {}: {}".format(j["groupName"], getattr(e, "message", repr(e))))
+                    break
+
+                details = response.json()
+
+                for det in details["response"]:
+                    seen_issues[det["issueId"]] = det["issueMessage"]
+                    mt = MessageType.WARNING
+                    if det["priority"] == "P1":
+                        mt = MessageType.BAD
+                    spark.post_to_spark(C.WEBEX_TEAM, ROOM, det["issueMessage"], mt)
+
+        if not j["pagination"]["next"]:
+            break
+
+        i += 1
+
+    for group in prev_state["groups"]:
+        if group not in seen_groups:
+            spark.post_to_spark(C.WEBEX_TEAM, ROOM, prev_state["groups"][group], MessageType.GOOD)
+
+    prev_state["start_time"] = end_time
+    prev_state["groups"] = seen_groups
+
+    with open(CACHE_FILE, "w") as fd:
+        json.dump(fd, prev_state, indent=4)