Esempio n. 1
0
def jenkins(ALERTID=None, JOBNAME=None, TOKEN=None):
    """
    If called, run a Jenkins job without parameters -- request results are discarded.
    Requires `JENKINSURL defined in the form `https://jenkins.domain.com`.
    If `JOBNAME` and `TOKEN` are not passed then the must be defined
    For more information, see https://wiki.jenkins-ci.org/display/JENKINS/Remote+access+API
    """
    if not JENKINSURL or (not JENKINSJOBNAME
                          and not JOBNAME) or (not JENKINSTOKEN and not TOKEN):
        return ("Parameters must be set, please edit the shim!", 500, None)

    # We need to make the Jenkins URL
    if TOKEN:
        URL = JENKINSURL + "/job/" + JOBNAME + "/build?token=" + TOKEN
    else:
        URL = JENKINSURL + "/job/" + JENKINSJOBNAME + "/build?token=" + JENKINSTOKEN

    # No need to parse the request as we just want to run a job
    #a = parse(request)
    #payload = {
    #    "body": a['info'],
    #    "title": a['AlertName'],
    #    "type": "link",
    #    "url": a['url'],
    #}
    payload = ''

    headers = ''

    if headers:
        return callapi(URL, 'post', json.dumps(payload), headers)
    else:
        return callapi(URL, 'post', json.dumps(payload))
Esempio n. 2
0
def jira(ALERTID=None, PROJECT=None, ISSUETYPE='Bug'):
    """
    Create a new bug for every incoming webhook that does not already have an unresolved bug.
    If an bug is currently unresolved, add a new comment to the unresolved bug.
    If `ISSUETYPE` is passed, blindly attempt to open/check the specified `ISSUETYPE`.
    Requires JIRA* parameters to be defined.
    """

    bauth = request.authorization
    if bauth is not None:
        global JIRAUSER
        global JIRAPASS
        JIRAUSER = bauth.username
        JIRAPASS = bauth.password

    if not JIRAURL or not JIRAUSER or not JIRAPASS or not PROJECT:
        return ("JIRA* parameters must be set, please edit the shim!", 500,
                None)

    headers = {'Content-type': 'application/json'}
    a = parse(request)

    # Get the list of unresolved incidents that contain the AlertName from the incoming webhook
    incident = callapi(
        JIRAURL + '/rest/api/2/search?jql=project=' + PROJECT +
        '+AND+resolution=unresolved+AND+summary~"' + a['AlertName'] + '"',
        'get', None, headers, (JIRAUSER, JIRAPASS))

    try:
        i = json.loads(incident)
    except:
        return incident

    try:  # Determine if there is an unresolved incident already
        if i['issues'][0]['key'] is not None:
            # Option 1: Do nothing
            #logging.info('Nothing to do, exiting.')
            #return ("OK", 200, None)

            # Option 2: Add a new comment
            payload = {"body": a['moreinfo']}
            return callapi(
                JIRAURL + '/rest/api/2/issue/' + i['issues'][0]['key'] +
                '/comment', 'put', json.dumps(payload), headers,
                (JIRAUSER, JIRAPASS))
    except:  # If no open incident then open one
        payload = {
            "project": {
                "key": PROJECT
            },
            "fields": {
                "summary": a['AlertName'],
                "description": a['moreinfo'],
                "issuetype": {
                    "name": ISSUETYPE
                }
            }
        }
        return callapi(JIRAURL + '/rest/api/2/issue/', 'post',
                       json.dumps(payload), headers, (JIRAUSER, JIRAPASS))
Esempio n. 3
0
def test_callapi():
    try:
        loginsightwebhookdemo.callapi()
    except TypeError:
        assert True
    else:
        assert False
    try:
        loginsightwebhookdemo.callapi('abc123')
    except (requests.exceptions.MissingSchema):
        assert True
    else:
        assert False
    try:
        loginsightwebhookdemo.callapi('http://abc123')
    except (requests.exceptions.ConnectionError):
        assert True
    else:
        assert False
    assert 'method' in loginsightwebhookdemo.callapi(
        'http://httpbin.org/anything', 'get')
    assert 'authenticated' in loginsightwebhookdemo.callapi(
        'http://httpbin.org/basic-auth/user/passwd', 'get', None,
        {"Cache-control": "no-cache"}, ('user', 'passwd'), False)
    print(
        loginsightwebhookdemo.callapi('http://httpbin.org/status/400', 'get',
                                      'test'))
    assert 400 == loginsightwebhookdemo.callapi(
        'http://httpbin.org/status/400', 'get', 'test')[1]
Esempio n. 4
0
def jenkins(ALERTID=None, JOBNAME=None, TOKEN=None):
    """
    If called, run a Jenkins job without parameters -- request results are discarded.
    Requires `JENKINSURL defined in the form `https://jenkins.domain.com`.
    If `JOBNAME` and `TOKEN` are not passed then the must be defined
    For more information, see https://wiki.jenkins-ci.org/display/JENKINS/Remote+access+API
    """
    if not JENKINSURL or (not JENKINSJOBNAME and not JOBNAME) or (not JENKINSTOKEN and not TOKEN):
        return ("Parameters must be set, please edit the shim!", 500, None)

    # We need to make the Jenkins URL
    if TOKEN:
        URL = JENKINSURL + "/job/" + JOBNAME + "/build?token=" + TOKEN
    else:
        URL = JENKINSURL + "/job/" + JENKINSJOBNAME + "/build?token=" + JENKINSTOKEN

    # No need to parse the request as we just want to run a job
    #a = parse(request)
    #payload = {
    #    "body": a['info'],
    #    "title": a['AlertName'],
    #    "type": "link",
    #    "url": a['url'],
    #}
    payload = ''

    headers = ''

    if headers:
        return callapi(URL, 'post', json.dumps(payload), headers)
    else:
        return callapi(URL, 'post', json.dumps(payload))
Esempio n. 5
0
def servicenow(ALERTID=None):
    """
    Create a new incident for every incoming webhook that does not already have an active incident.
    If an incident is already active, add a new comment to the active alert.
    Uniqueness is determined by the incoming webhook alert name. Incidents are opened by the user defined.
    Requires SERVICENOW* parameters to be defined.
    """

    if not SERVICENOWURL or not SERVICENOWUSER or not SERVICENOWPASS:
        return ("SERVICENOW* parameters must be set, please edit the shim!",
                500, None)

    headers = {
        'Content-type': 'application/json',
        'Accept': 'application/json'
    }
    a = parse(request)
    payload = {"comments": a['moreinfo']}

    # Get the sys_id for the user
    user = callapi(
        SERVICENOWURL + '/sys_user.do?JSONv2&sysparm_query=user_name=' +
        SERVICENOWUSER + '&sysparam_fields=sys_id', 'get', None, headers,
        (SERVICENOWUSER, SERVICENOWPASS))
    try:
        u = json.loads(user)
    except:
        return user

    # Get the list of open incidents that contain the AlertName from the incoming webhook
    # Note the user may have been changed so do not query for the user
    incident = callapi(
        SERVICENOWURL +
        '/incident.do?JSONv2&sysparm_query=active=true^short_description=' +
        a['AlertName'], 'get', None, headers, (SERVICENOWUSER, SERVICENOWPASS))
    try:
        i = json.loads(incident)
    except:
        return incident

    try:  # Determine if there is an open incident already
        if i['records'][0]['active'] == 'true':
            # Option 1: Do nothing
            #logging.info('Nothing to do, exiting.')
            #return ("OK", 200, None)

            # Option 2: Add a new comment
            return callapi(
                SERVICENOWURL + '/api/now/v1/table/incident/' +
                i['records'][0]['sys_id'], 'put', json.dumps(payload), headers,
                (SERVICENOWUSER, SERVICENOWPASS))
    except:  # If no open incident then open one
        payload.update({
            "short_description": a['AlertName'],
            "caller_id": u['records'][0]['sys_id']
        })
        return callapi(SERVICENOWURL + '/api/now/v1/table/incident', 'post',
                       json.dumps(payload), headers,
                       (SERVICENOWUSER, SERVICENOWPASS))
Esempio n. 6
0
def zendesk(ALERTID=None, EMAIL=None, TOKEN=None):
    """
    Create a new incident for every incoming webhook that does not already have an open incident.
    If an incident is already open, add a new comment to the open alert.
    Uniqueness is determined by the incoming webhook alert name.
    Requires ZENDESK* parameters to be defined.
    """

    if (not ZENDESKURL or (not ZENDESKUSER and not EMAIL) or (not ZENDESKPASS and not ZENDESKTOKEN and not TOKEN)):
        return ("ZENDESK* parameters must be set, please edit the shim!", 500, None)
    if not ZENDESKUSER:
        USER = EMAIL
    else:
        USER = ZENDESKUSER
    # Prefer tokens over passwords
    if ZENDESKTOKEN or TOKEN:
        if ZENDESKTOKEN:
            USER = USER + '/token'
            PASS = ZENDESKTOKEN
        else:
            USER = USER + '/token'
            PASS = TOKEN
    else:
        PASS = ZENDESKPASS

    headers = {'Content-type': 'application/json', 'Accept': 'application/json'}
    a = parse(request)

    # Get the list of open incidents that contain the AlertName from the incoming webhook
    incident = callapi(ZENDESKURL + '/api/v2/search.json?query=type:ticket status:open subject:"' + a['AlertName'] + '"', 'get', None, headers, (USER, PASS))
    i = json.loads(incident)

    try: # Determine if there is an open incident already
        if i['results'][0]['id'] is not None:
            # Option 1: Do nothing
            #logging.info('Nothing to do, exiting.')
            #return ("OK", 200, None)

            # Option 2: Add a new comment
            # Limited to 30 updates per 10 minutes (https://developer.zendesk.com/rest_api/docs/core/introduction)
            payload = { 'ticket': { 'comment': { 'body': a['moreinfo'] } } }
            return callapi(ZENDESKURL + '/api/v2/tickets/' + str(i['results'][0]['id']) + '.json', 'put', json.dumps(payload), headers, (USER, PASS))
    except: # If no open incident then open one
        payload = {
            "ticket": {
                #"requester": {
                #    "name": "Log Insight",
                #    "email": USER
                #},
                "subject": a['AlertName'],
                "comment": {
                    "body": a['moreinfo'],
                },
                "type": 'incident',
                "tags": ["loginsight"]
            }
        }
        return callapi(ZENDESKURL + '/api/v2/tickets.json', 'post', json.dumps(payload), headers, (USER, PASS))
Esempio n. 7
0
def test_bugzilla_e2e():
    url = URL + '/rest/bug?api_key=' + TOKEN + '&product=' + PRODUCT + '&component=' + COMPONENT + '&summary=' + json.loads(
        payload)['AlertName']
    id = json.loads(loginsightwebhookdemo.callapi(url, 'get'))['bugs'][0]['id']
    url = URL + '/rest/bug/' + str(
        id
    ) + '/comment?api_key=' + TOKEN + '&product=' + PRODUCT + '&component=' + COMPONENT + '&summary=' + json.loads(
        payload)['AlertName']
    assert json.loads(loginsightwebhookdemo.callapi(url, 'get'))['bugs'][str(
        id)]['comments'][1]['text'].startswith('Alert Name: ')
Esempio n. 8
0
def test_callapi():
    try:
        loginsightwebhookdemo.callapi()
    except TypeError:
        assert True
    else:
        assert False
    try:
        loginsightwebhookdemo.callapi('abc123')
    except (requests.exceptions.MissingSchema):
        assert True
    else:
        assert False
    try:
        loginsightwebhookdemo.callapi('http://abc123')
    except (requests.exceptions.ConnectionError):
        assert True
    else:
        assert False
    assert 'google.j' in loginsightwebhookdemo.callapi('http://www.google.com', 'get')
    assert 'google.j' in loginsightwebhookdemo.callapi('http://www.google.com', 'get', None, {"Cache-control": "no-cache"}, ('user', 'pass'), False)
    if any('400' in code for code in loginsightwebhookdemo.callapi('http://www.google.com', 'get', 'test')):
        assert True
    else:
        assert False
Esempio n. 9
0
def test_callapi():
    try:
        loginsightwebhookdemo.callapi()
    except TypeError:
        assert True
    else:
        assert False
    try:
        loginsightwebhookdemo.callapi('abc123')
    except (requests.exceptions.MissingSchema):
        assert True
    else:
        assert False
    try:
        loginsightwebhookdemo.callapi('http://abc123')
    except (requests.exceptions.ConnectionError):
        assert True
    else:
        assert False
    assert 'google.j' in loginsightwebhookdemo.callapi('http://www.google.com',
                                                       'get')
    assert 'google.j' in loginsightwebhookdemo.callapi(
        'http://www.google.com', 'get', None, {"Cache-control": "no-cache"},
        ('user', 'pass'), False)
    if any('400' in code for code in loginsightwebhookdemo.callapi(
            'http://www.google.com', 'get', 'test')):
        assert True
    else:
        assert False
Esempio n. 10
0
def jira(ALERTID=None, PROJECT=None, ISSUETYPE='Bug'):
    """
    Create a new bug for every incoming webhook that does not already have an unresolved bug.
    If an bug is currently unresolved, add a new comment to the unresolved bug.
    If `ISSUETYPE` is passed, blindly attempt to open/check the specified `ISSUETYPE`.
    Requires JIRA* parameters to be defined.
    """

    bauth = request.authorization
    if bauth is not None:
        global JIRAUSER
        global JIRAPASS
        JIRAUSER = bauth.username
        JIRAPASS = bauth.password

    if not JIRAURL or not JIRAUSER or not JIRAPASS or not PROJECT:
        return ("JIRA* parameters must be set, please edit the shim!", 500, None)

    headers = {'Content-type': 'application/json'}
    a = parse(request)

    # Get the list of unresolved incidents that contain the AlertName from the incoming webhook
    incident = callapi(JIRAURL + '/rest/api/2/search?jql=project=' + PROJECT + '+AND+resolution=unresolved+AND+summary~"' + a['AlertName'] + '"', 'get', None, headers, (JIRAUSER, JIRAPASS))

    try:
        i = json.loads(incident)
    except:
        return incident

    try: # Determine if there is an unresolved incident already
        if i['issues'][0]['key'] is not None:
            # Option 1: Do nothing
            #logging.info('Nothing to do, exiting.')
            #return ("OK", 200, None)

            # Option 2: Add a new comment
            payload = { "body": a['moreinfo'] }
            return callapi(JIRAURL + '/rest/api/2/issue/' + i['issues'][0]['key'] + '/comment', 'put', json.dumps(payload), headers, (JIRAUSER, JIRAPASS))
    except: # If no open incident then open one
        payload = {
            "project": {
                "key": PROJECT
            },
            "fields": {
                "summary": a['AlertName'],
                "description": a['moreinfo'],
                "issuetype": {
                    "name": ISSUETYPE
                }
            }
        }
        return callapi(JIRAURL + '/rest/api/2/issue/', 'post', json.dumps(payload), headers, (JIRAUSER, JIRAPASS))
Esempio n. 11
0
def servicenow(ALERTID=None):
    """
    Create a new incident for every incoming webhook that does not already have an active incident.
    If an incident is already active, add a new comment to the active alert.
    Uniqueness is determined by the incoming webhook alert name. Incidents are opened by the user defined.
    Requires SERVICENOW* parameters to be defined.
    """

    bauth = request.authorization
    if bauth is not None:
        global SERVICENOWUSER
        global SERVICENOWPASS
        SERVICENOWUSER = bauth.username
        SERVICENOWPASS = bauth.password

    if not SERVICENOWURL or not SERVICENOWUSER or not SERVICENOWPASS:
        return ("SERVICENOW* parameters must be set, please edit the shim!", 500, None)

    headers = {'Content-type': 'application/json', 'Accept': 'application/json'}
    a = parse(request)
    payload = { "comments": a['moreinfo'] }

    # Get the sys_id for the user
    user = callapi(SERVICENOWURL + '/sys_user.do?JSONv2&sysparm_query=user_name=' + SERVICENOWUSER + '&sysparam_fields=sys_id', 'get', None, headers, (SERVICENOWUSER, SERVICENOWPASS))
    try:
        u = json.loads(user)
    except:
        return user

    # Get the list of open incidents that contain the AlertName from the incoming webhook
    # Note the user may have been changed so do not query for the user
    incident = callapi(SERVICENOWURL + '/incident.do?JSONv2&sysparm_query=active=true^short_description=' + a['AlertName'], 'get', None, headers, (SERVICENOWUSER, SERVICENOWPASS))
    try:
        i = json.loads(incident)
    except:
        return incident

    try: # Determine if there is an open incident already
        if i['records'][0]['active'] == 'true':
            # Option 1: Do nothing
            #logging.info('Nothing to do, exiting.')
            #return ("OK", 200, None)

            # Option 2: Add a new comment
            return callapi(SERVICENOWURL + '/api/now/v1/table/incident/' + i['records'][0]['sys_id'], 'put', json.dumps(payload), headers, (SERVICENOWUSER, SERVICENOWPASS))
    except: # If no open incident then open one
        payload.update({
            "short_description": a['AlertName'],
            "caller_id": u['records'][0]['sys_id']
        })
        return callapi(SERVICENOWURL + '/api/now/v1/table/incident', 'post', json.dumps(payload), headers, (SERVICENOWUSER, SERVICENOWPASS))
Esempio n. 12
0
def jenkins(ALERTID=None, JOBNAME=None, TOKEN=None):
    """
    If called, run a Jenkins job without parameters -- request results are discarded.
    Requires `JENKINSURL defined in the form `https://jenkins.domain.com`.
    If `JOBNAME` and `TOKEN` are not passed then the must be defined
    For more information, see https://wiki.jenkins-ci.org/display/JENKINS/Remote+access+API
    """
    if not JENKINSURL or (not JENKINSJOBNAME
                          and not JOBNAME) or (not JENKINSTOKEN and not TOKEN):
        return ("Parameters must be set, please edit the shim!", 500, None)

    # We need to make the Jenkins URL
    #if TOKEN:
    #    URL = JENKINSURL + "/job/" + JOBNAME + "/build?token=" + TOKEN
    #else:
    #    URL = JENKINSURL + "/job/" + JENKINSJOBNAME + "/build?token=" + JENKINSTOKEN

    # No need to parse the request as we just want to run a job
    #a = parse(request)
    #payload = {
    #    "body": a['info'],
    #    "title": a['AlertName'],
    #    "type": "link",
    #    "url": a['url'],
    #}
    URL = JENKINSURL
    payload = {
        "body":
        "[[PizzaHouse]](http://url_to_text) You have a new Pizza order.",
        "connectColor":
        "#FAC11B",
        "connectInfo": [{
            "title": "Topping",
            "description": "Pepperoni"
        }, {
            "title": "Location",
            "description": "Empire State Building, 5th Ave, New York",
            "imageUrl": "http://url_to_text"
        }]
    }

    headers = {
        'Accept': 'application/vnd.tosslab.jandi-v2+json',
        'Content-Type': 'application/json'
    }

    if headers:
        return callapi(URL, 'post', json.dumps(payload), headers)
    else:
        return callapi(URL, 'post', json.dumps(payload))
Esempio n. 13
0
def pivotaltracker(ALERTID=None, TOKEN=None, PROJECT=None):
    """
    Create a new bug for every incoming webhook that does not already have an existing one.
    If a bug already exists, do nothing.
    Uniqueness is determined by the incoming webhook alert name.
    Requires PIVOTALTRACKER* parameters to be defined.
    """
    if (not PIVOTALTRACKERURL or (not PIVOTALTRACKERTOKEN and not TOKEN)
            or (not PIVOTALTRACKERPROJECT and not PROJECT)):
        return (
            "PIVOTALTRACKER* parameters must be set, please edit the shim!",
            500, None)
    if not PROJECT:
        TOKEN = PIVOTALTRACKERTOKEN
        PROJECT = PIVOTALTRACKERPROJECT

    a = parse(request)

    # Defaults to Content-type: application/json
    # If changed you must specify the content-type manually
    headers = {'Content-type': 'application/json', 'X-TrackerToken': TOKEN}

    # Get the list of open bugs that contain the AlertName from the incoming webhook
    bug = callapi(
        PIVOTALTRACKERURL + PROJECT + '/stories?filter=name:"' +
        a['AlertName'] + '"', 'get', None, headers, None)
    try:
        b = json.loads(bug)
    except:
        return bug

    try:  # Determine if there is an open incident already
        if b[0] is not None:
            # Option 1: Do nothing
            logging.debug('Nothing to do, exiting.')
            return ("OK", 200, None)

            # Option 2: Add a new comment
            #payload = { 'ticket': { 'comment': { 'body': a['moreinfo'] } } }
            #return callapi(PIVOTALTRACKERURL + '/api/v2/tickets/' + str(i['results'][0]['id']) + '.json', 'put', json.dumps(payload), headers, (USER, PASS))
    except:  # If no open bug then open one
        payload = {
            "name": a['AlertName'],
            "description": a['moreinfo'],
            "story_type": "bug"
        }
        return callapi(PIVOTALTRACKERURL + PROJECT + '/stories', 'post',
                       json.dumps(payload), headers, None)
Esempio n. 14
0
def manageengine(TOKEN=None, ALERTID=None):
    """
    Create a new incident for the bigpanda service identified by `APIKEY` in the URL.
    Uses https://www.manageengine.com/products/service-desk/sdpod-v3-api/SDPOD-V3-API.html.
    """
    if not MANAGEENGINEURL:
        return ("MANAGEENGINEURL parameter must be set properly, please edit the shim!", 500, None)
    if not TOKEN:
        return ("TOKEN must be set in the URL (e.g. /endpoint/manageengine/<TOKEN>/<APPKEY>", 500, None)
    HEADERS = {"Accept": "application/json", "Content-Type": "application/json", "TECHNICIAN_KEY": TOKEN}

    # Retrieve fields in notification
    a = parse(request)

    payload = {
        input_data = "request": {
        "subject": a['description'],
        "description": a['moreinfo'],
        "requester": {
            "name": "TICKET OPENER"
        },
        "group": {
            "name": "ASSIGNMENT GROUP"
        },
        "technician": {
            "name": "TECHNICIAN ASSIGNMENT"
        }
    }
    }
    return callapi(MANAGEENGINEURL, 'post', json.dumps(payload), HEADERS)
Esempio n. 15
0
def opsgenie(APIKEY=None, TEAM=None, ALERTID=None):
    """
    Create a new incident for the opsgenie service identified by `APIKEY` in the URL.
    Uses https://www.opsgenie.com/docs/web-api/alert-api#createAlertRequest.
    """
    if not OPSGENIEURL:
        return (
            "OPSGENIEURL parameter must be set properly, please edit the shim!",
            500, None)
    if not APIKEY:
        return (
            "APIKEY must be set in the URL (e.g. /endpoint/opsgenie/<APIKEY>",
            500, None)

    # Retrieve fields in notification
    a = parse(request)

    payload = {
        "apiKey": APIKEY,
        "alias": a['AlertName'],
        "message": a['AlertName'],
        "details": {
            "notes": a['info'],
            "events": str(a['Messages']),
        },
        "description": a['moreinfo']
    }
    if TEAM is not None:
        payload.append({"teams": [TEAM]})
    return callapi(OPSGENIEURL, 'post', json.dumps(payload))
Esempio n. 16
0
def bigpanda(TOKEN=None, APPKEY=None, ALERTID=None):
    """
    Create a new incident for the bigpanda service identified by `APIKEY` in the URL.
    Uses https://docs.bigpanda.io/reference#alerts.
    """
    if not BIGPANDAURL:
        return (
            "BIGPANDAURL parameter must be set properly, please edit the shim!",
            500, None)
    if not TOKEN:
        return (
            "TOKEN must be set in the URL (e.g. /endpoint/bigpanda/<TOKEN>/<APPKEY>",
            500, None)
    if not APPKEY:
        return (
            "APPKEY must be set in the URL (e.g. /endpoint/bigpanda/<TOKEN>/<APPKEY>",
            500, None)
    HEADERS = {
        "Accept": "application/json",
        "Content-Type": "application/json",
        "Authorization": "Bearer " + TOKEN
    }

    # Retrieve fields in notification
    a = parse(request)

    payload = {
        "app_key": APPKEY,
        "host": "Webhook Shim",
        "check": a['AlertName'],
        "description": a['moreinfo']
    }
    return callapi(BIGPANDAURL, 'post', json.dumps(payload), HEADERS)
Esempio n. 17
0
def opsgenie(APIKEY=None, TEAM=None, ALERTID=None):
    """
    Create a new incident for the opsgenie service identified by `APIKEY` in the URL.
    Uses https://www.opsgenie.com/docs/web-api/alert-api#createAlertRequest.
    """
    if not OPSGENIEURL:
        return ("OPSGENIEURL parameter must be set properly, please edit the shim!", 500, None)
    if not APIKEY:
        return ("APIKEY must be set in the URL (e.g. /endpoint/opsgenie/<APIKEY>", 500, None)

    # Retrieve fields in notification
    a = parse(request)

    payload = {
        "apiKey": APIKEY,
        "alias": a['AlertName'],
        "message": a['AlertName'],
        "details": {
            "notes": a['info'],
            "events": str(a['Messages']),
        },
        "description": a['moreinfo']
    }
    if TEAM is not None:
        payload.append({"teams": [TEAM]})
    return callapi(OPSGENIEURL, 'post', json.dumps(payload))
Esempio n. 18
0
def pagerduty(SERVICEKEY=None, ALERTID=None):
    """
    Create a new incident for the Pagerduty service identified by `SERVICEKEY` in the URL.
    Uses the https://v2.developer.pagerduty.com/v2/docs/trigger-events API directly.
    """
    if not PAGERDUTYURL:
        return ("PAGERDUTYURL parameter must be set properly, please edit the shim!", 500, None)
    if not SERVICEKEY:
        return ("SERVICEKEY must be set in the URL (e.g. /endpoint/pagerduty/<SERVICEKEY>", 500, None)

    # Retrieve fields in notification
    a = parse(request)

    payload = {
        "service_key": SERVICEKEY,
        "event_type": "trigger",
        "description": a['AlertName'],
        "details": {
            "notes": a['info'],
            "events": str(a['Messages']),
        },
        "contexts": [
            {
                "type": "link",
                "href": a['url'],
                "text": "View search results"
            }, {
                "type": "link",
                "href": a['editurl'],
                "text": "View alert definition"
            },
        ]
    }
    return callapi(PAGERDUTYURL, 'post', json.dumps(payload))
Esempio n. 19
0
def pushbullet(ALERTID=None, TOKEN=None):
    """
    Send a `link` notification to all devices on pushbullet with a link back to the alert's query.
    If `TOKEN` is not passed, requires `PUSHBULLETTOKEN` defined, see https://www.pushbullet.com/#settings/account
    """
    #if not PUSHBULLETURL:
    #return ("PUSHBULLET parameter must be set, please edit the shim!", 500, None)
    #if (TOKEN is not None):
    #PUSHBULLETTOKEN = TOKEN
    #if not PUSHBULLETTOKEN:
    #   return ("PUSHBULLETTOKEN parameter must be set, please edit the shim!", 500, None)
    if not PUSHBULLETTOKEN:
        return ("fail", 500, None)

    a = parse(request)

    payload = {
        "body": a['info'],
        "title": a['AlertName'],
        "type": "link",
        "url": a['url'],
    }

    headers = {
        'Content-type': 'application/json',
        'Accept': 'application/vnd.tosslab.jandi-v2+json'
    }

    return callapi(PUSHBULLETURL, 'post', json.dumps(payload), headers)
Esempio n. 20
0
def opsgenie(APIKEY=None, ALERTID=None):
    """
    Create a new incident for the opsgenie service identified by `APIKEY` in the URL.
    Uses https://docs.opsgenie.com/docs/alert-api.
    """
    if not OPSGENIEURL:
        return (
            "OPSGENIEURL parameter must be set properly, please edit the shim!",
            500, None)
    if not APIKEY:
        return (
            "APIKEY must be set in the URL (e.g. /endpoint/opsgenie/<APIKEY>",
            500, None)
    HEADERS = {
        "Content-type": "application/json",
        "Authorization": "GenieKey " + APIKEY
    }

    # Retrieve fields in notification
    a = parse(request)

    payload = {
        "alias": a['AlertName'],
        "message": a['AlertName'],
        "description": a['moreinfo']
    }
    return callapi(OPSGENIEURL, 'post', json.dumps(payload), HEADERS)
Esempio n. 21
0
def slack(NUMRESULTS=10, ALERTID=None, T=None, B=None, X=None):
    """
    Consume messages, and send them to Slack as an Attachment object.
    Sends up to `NUMRESULTS` (default 10) events onward.
    If `T/B/X` is not passed, requires `SLACKURL` defined in the form `https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX`
    For more information, see https://api.slack.com/incoming-webhooks
    """
    # Prefer URL parameters to SLACKURL
    if X is not None:
        URL = 'https://hooks.slack.com/services/' + T + '/' + B + '/' + X
    elif not SLACKURL or not 'https://hooks.slack.com/services' in SLACKURL:
        return (
            "SLACKURL parameter must be set properly, please edit the shim!",
            500, None)
    else:
        URL = SLACKURL

    a = parse(request)

    slack_attachments = []
    if (a['color'] == 'red'):
        color = 'danger'
    elif (a['color'] == 'yellow'):
        color = 'warning'
    else:
        color = 'info'
    payload = {
        "icon_url": a['icon'],
    }
    try:
        if ('AlertName' in a):
            # remove "Alert Details" field in 'moreinfo'
            tmp = a['moreinfo']
            tmp = tmp.strip().split('\n')
            tmp.remove('')
            [tmp.remove(t) for t in tmp if t.startswith('Alert Details')]
            tmp = "\n".join(tmp)
            # end removal

            slack_attachments.append({
                "pretext": tmp,
            })
            if ('Messages' in a):
                for message in a['Messages'][:NUMRESULTS]:
                    slack_attachments.append(slack_fields(color, message))
            if a['fields']:
                slack_attachments.append(slack_fields(color, a))
    except:
        logging.exception(
            "Can't create new payload. Check code and try again.")
        raise

    payload.update({
        "username": a['hookName'],
        "attachments": slack_attachments
    })
    return callapi(URL, 'post', json.dumps(payload))
Esempio n. 22
0
def groove(ALERTID=None, TOKEN=None, FROM=None, TO=None):
    """
    Create a new ticket for every incoming webhook.
    Groove does not support searching for open tickets by subject today.
    Requires GROOVE* parameters to be defined.
    """
    if not GROOVEURL or (not GROOVEFROM and not FROM) or (not GROOVETO and not TO):
        return ("GROOVE* parameters must be set, please edit the shim!", 500, None)
    if TOKEN is None:
        return ("TOKEN must be passed in the URL, please edit the incoming webhook!", 500, None)
    if GROOVEFROM and not FROM:
        FROM = GROOVEFROM
    if GROOVETO and not TO:
        TO = GROOVETO

    a = parse(request)

    headers = { 'Content-type': 'application/json', 'Authorization': 'Bearer ' + TOKEN }

    # Unfortunately, the Groove API does not support searching for open tickets by subject today
    # https://www.groovehq.com/docs/tickets#finding-one-ticket
    # As a result, every incoming webhook will result in a new ticket
    # Commented sections has been wired for when the Groove API is updated to support the use case

    ## Get the list of open incidents that contain the AlertName from the incoming webhook
    # payload = {
    #     "state": "notstarted,opened,pending",
    #     "subject": a['AlertName']
    # }
    # incident = callapi(GROOVEURL + '/tickets', 'get', payload, headers)
    #
    # try:
    #   i = json.loads(incident)
    # except:
    #   return incident

    # try: # Determine if there is an open incident already
    #     if i['tickets'][0]['number'] is not None:
    #         # Option 1: Do nothing
    #         #logging.info('Nothing to do, exiting.')
    #         #return ("OK", 200, None)

    #         # Option 2: Add a new message
    #         payload = { 'body': a['moreinfo'] }
    #         return callapi(GROOVEURL + '/tickets/' + str(i['tickets'][0]['number']) + '/messages', 'put', json.dumps(payload), headers)
    # except: # If no open incident then open one
    payload = {
        "ticket": {
            "body": a['moreinfo'],
            "from": FROM,
            "to": TO,
            "subject": a['AlertName'],
            "tags": ["loginsight"]
        }
    }
    return callapi(GROOVEURL + '/tickets', 'post', json.dumps(payload), headers)
Esempio n. 23
0
def moogsoft(ALERTID=None):

    """
    Information about this shim.
    Requires moogsoft* parameters to be defined.
    """
    bauth = request.authorization
    if bauth is not None:
        global moogsoftUSER
        global moogsoftPASS
        moogsoftUSER = bauth.username
        moogsoftPASS = bauth.password

    if (not moogsoftURL or (not moogsoftUSER ) or (not moogsoftPASS) or (not vropsURL) or (not vropsUser) or (not vropsPass)):
        return ("moogsoft* and vrops* parameters must be set, please edit the shim!", 500, None)

    a = parse(request)

########################################
#Map vROps crticiality to moog sev here
########################################
    sevMap = {
        "ALERT_CRITICALITY_LEVEL_CRITICAL":5,
        "ALERT_CRITICALITY_LEVEL_IMMEDIATE":4,
        "ALERT_CRITICALITY_LEVEL_WARNING":3,
        "ALERT_CRITICALITY_LEVEL_INFO":2
    }
    link = vropsURL+"/ui/index.action#/object/"+a['resourceId']+"/alertsAndSymptoms/alerts/"+ALERTID
    recommendation = recommendations(a['alertId'])
    resourceProperties = fetchResourceProperties(a['resourceId'])

    payload = {
        "signature":ALERTID,
        "source_id":a['resourceId'],
        "external_id":ALERTID,
        "manager":a['hookName'],
        "source":a['resourceName'] if (a['resourceName'] != "") else "undefined",
        "class":a['subType'],
        "agent":a['adapterKind'],
        "agent_location":"",
        "type":a['type']+"::"+a['subType'],
        "severity":sevMap[a['criticality']] if (a['status'] != 'CANCELED') else 0,
        "description":a['AlertName'],
        "agent_time":a['updateDate']/1000,
        "recommendation":recommendation,
        "resource_properties":resourceProperties,
        "link":link
    }

    # Defaults to Content-type: application/json
    # If changed you must specify the content-type manually
    headers = {'Content-type': 'application/json', 'Accept': 'application/json'}
    if not headers:
        headers = None

    return callapi(moogsoftURL, 'post', json.dumps(payload), headers, check=VERIFY)
Esempio n. 24
0
def msteams(NUMRESULTS=10, ALERTID=None):
    """
    Posts a message to a Microsoft Teams channel. Set TEAMSURL to the incoming
    webhook URL provided by Teams. To create a Teams webhook see:
    http://aka.ms/o365-connectors
    """

    if not TEAMSURL:
        return ("The TEAMSURL parameter must be set, please edit the shim!", 500, None)

    a = parse(request)

    teams_attachments = [
        {
            "activityImage": a['icon'],
            "activityTitle": a['AlertName'] if 'AlertName' in a else "Alert details",
            "activitySubtitle": "[Link to Alert](" + a['url'] + ")" if a['url'] else "",
        }
    ]

    try:
        if ('AlertName' in a):
            if ('Messages' in a):
                for message in a['Messages'][:NUMRESULTS]:
                    teams_attachments.append(teams_fields(message))
            if (a['fields'] is not None):
                teams_attachments.append(teams_fields(a))
    except:
        logging.exception("Can't create new payload. Check code and try again.")
        raise

    if (a['color'] == 'red'):
        color = 'CC0000'
    elif (a['color'] == 'yellow'):
        color = 'FFCC00'
    elif (a['color'] == 'green'):
        color = '009000'
    else:
        color = '0075FF'

    payload = {
        "@type": "MessageCard",
        "@context": "http://schema.org/extensions",
        "themeColor": color,
        "summary": "Message from " + a['hookName'],
        "sections": teams_attachments
    }

    # Defaults to Content-type: application/json
    # If changed you must specify the content-type manually
    headers = {'Content-type': 'application/json', 'Accept': 'application/json'}
    if not headers:
        headers = None

    return callapi(TEAMSURL, 'post', json.dumps(payload), headers)
def pivotaltracker(ALERTID=None, TOKEN=None, PROJECT=None):
    """
    Create a new bug for every incoming webhook that does not already have an existing one.
    If a bug already exists, do nothing.
    Uniqueness is determined by the incoming webhook alert name.
    Requires PIVOTALTRACKER* parameters to be defined.
    """
    if (not PIVOTALTRACKERURL or (not PIVOTALTRACKERTOKEN and not TOKEN) or (not PIVOTALTRACKERPROJECT and not PROJECT)):
        return ("PIVOTALTRACKER* parameters must be set, please edit the shim!", 500, None)
    if not PROJECT:
        TOKEN = PIVOTALTRACKERTOKEN
        PROJECT = PIVOTALTRACKERPROJECT

    a = parse(request)

    # Defaults to Content-type: application/json
    # If changed you must specify the content-type manually
    headers = {'Content-type': 'application/json', 'X-TrackerToken': TOKEN}

    # Get the list of open bugs that contain the AlertName from the incoming webhook
    bug = callapi(PIVOTALTRACKERURL + PROJECT + '/stories?filter=name:"' + a['AlertName'] + '"', 'get', None, headers, None)
    try:
        b = json.loads(bug)
    except:
        return bug

    try: # Determine if there is an open incident already
        if b[0] is not None:
            # Option 1: Do nothing
            logging.debug('Nothing to do, exiting.')
            return ("OK", 200, None)

            # Option 2: Add a new comment
            #payload = { 'ticket': { 'comment': { 'body': a['moreinfo'] } } }
            #return callapi(PIVOTALTRACKERURL + '/api/v2/tickets/' + str(i['results'][0]['id']) + '.json', 'put', json.dumps(payload), headers, (USER, PASS))
    except: # If no open bug then open one
        payload = {
            "name": a['AlertName'],
            "description": a['moreinfo'],
            "story_type": "bug"
        }
        return callapi(PIVOTALTRACKERURL + PROJECT + '/stories', 'post', json.dumps(payload), headers, None)
Esempio n. 26
0
def fetchResourceProperties(resourceId=None):
    headers = {'Content-type': 'application/json', 'Accept': 'application/json'}
    alertURL = vropsURL+"api/resources/"+resourceId+"/properties"
    auth = (vropsUser, vropsPass)
    response = callapi(alertURL, method='get', payload=None, headers=headers, auth=auth, check=VERIFY)
    rawProps = json.loads(response)

    props = {}
    for prop in rawProps['property']:
        props[prop["name"]] = prop["value"]
    return props
Esempio n. 27
0
def recommendations(ALERTID=None):
    headers = {'Content-type': 'application/json', 'Accept': 'application/json'}
    alertURL = vropsURL+"api/alerts/"+ALERTID
    auth = (vropsUser, vropsPass)
    response = callapi(alertURL, method='get', payload=None, headers=headers, auth=auth, check=VERIFY)
# Fetch the alert to grab alert def ID
    alertInfo = json.loads(response)
    alertDescURL = vropsURL+"api/alertdefinitions/"+alertInfo['alertDefinitionId']
    response = callapi(alertDescURL, method='get', payload=None, headers=headers, auth=auth, check=VERIFY)
# Fetch recommendations from alert def
    recommendations = json.loads(response)
    if recommendations['states'][0]['recommendationPriorityMap']:
        for recommendation in recommendations['states'][0]['recommendationPriorityMap']:
            if recommendations['states'][0]['recommendationPriorityMap'][recommendation] == 1:
                alertDescURL = vropsURL+"api/recommendations/"+recommendation
                response = callapi(alertDescURL, method='get', payload=None, headers=headers, auth=auth, check=VERIFY)
                recText = json.loads(response)
                return recText['description']
    else:
        return
Esempio n. 28
0
def recommendations(ALERTID=None):
    headers = {
        'Content-type': 'application/json',
        'Accept': 'application/json'
    }
    alertURL = vropsURL + "api/alerts/" + ALERTID
    auth = (vropsUser, vropsPass)
    response = callapi(alertURL,
                       method='get',
                       payload=None,
                       headers=headers,
                       auth=auth,
                       check=VERIFY)
    # Fetch the alert to grab alert def ID
    alertInfo = json.loads(response)
    alertDescURL = vropsURL + "api/alertdefinitions/" + alertInfo[
        'alertDefinitionId']
    response = callapi(alertDescURL,
                       method='get',
                       payload=None,
                       headers=headers,
                       auth=auth,
                       check=VERIFY)
    # Fetch recommendations from alert def
    recommendations = json.loads(response)
    if recommendations['states'][0]['recommendationPriorityMap']:
        for recommendation in recommendations['states'][0][
                'recommendationPriorityMap']:
            if recommendations['states'][0]['recommendationPriorityMap'][
                    recommendation] == 1:
                alertDescURL = vropsURL + "api/recommendations/" + recommendation
                response = callapi(alertDescURL,
                                   method='get',
                                   payload=None,
                                   headers=headers,
                                   auth=auth,
                                   check=VERIFY)
                recText = json.loads(response)
                return recText['description']
    else:
        return
Esempio n. 29
0
def pagerduty(SERVICEKEY=None, ALERTID=None):
    if not SERVICEKEY:
        return (
            "SERVICEKEY must be set in the URL (e.g. /endpoint/pagerduty/<SERVICEKEY>",
            500, None)

    # Retrieve fields in notification
    a = parse(request)

    payload = {
        "payload": {
            "summary": a['AlertName'],
            "source": a['hookName'],
            "severity": "info",
            "custom_details": {
                "startDate": a['startDate'],
                "criticality": a['criticality'],
                "resourceId": a['resourceId'],
                "alertId": a['alertId'],
                "status": a['status'],
                "resourceName": a['resourceName'],
                "updateDate": a['updateDate'],
                "info": a['info'],
                "moreinfo": a['moreinfo'],
                "fields": a['fields']
            },
        },
        "routing_key":
        SERVICEKEY,
        "event_action":
        "trigger",
        "description":
        a['AlertName'],
        "details": {
            "notes": a['info'],
            "events": str(a['Messages']),
        },
        "contexts": [
            {
                "type": "link",
                "href": a['url'],
                "text": "View search results"
            },
            {
                "type": "link",
                "href": a['editurl'],
                "text": "View alert definition"
            },
        ]
    }
    return callapi(PAGERDUTYURL, 'post', json.dumps(payload))
Esempio n. 30
0
def test_callapi():
    try:
        loginsightwebhookdemo.callapi()
    except TypeError:
        assert True
    else:
        assert False
    try:
        loginsightwebhookdemo.callapi('abc123')
    except (requests.exceptions.MissingSchema):
        assert True
    else:
        assert False
    try:
        loginsightwebhookdemo.callapi('http://abc123')
    except (requests.exceptions.ConnectionError):
        assert True
    else:
        assert False
    assert 'method' in loginsightwebhookdemo.callapi('http://httpbin.org/anything', 'get')
    assert 'authenticated' in loginsightwebhookdemo.callapi('http://httpbin.org/basic-auth/user/passwd', 'get', None, {"Cache-control": "no-cache"}, ('user', 'passwd'), False)
    print(loginsightwebhookdemo.callapi('http://httpbin.org/status/400', 'get', 'test'))
    assert 400 == loginsightwebhookdemo.callapi('http://httpbin.org/status/400', 'get', 'test')[1]
Esempio n. 31
0
def template(ALERTID=None, TOKEN=None, EMAIL=None):
    """
    Information about this shim.
    Requires TEMPLATE* parameters to be defined.
    """
    if (not TEMPLATEURL or (not TEMPLATEUSER and not EMAIL)
            or (not TEMPLATEPASS and not TEMPLATETOKEN and not TOKEN)):
        return ("TEMPLATE* parameters must be set, please edit the shim!", 500,
                None)
    if not TEMPLATEUSER:
        USER = EMAIL
    else:
        USER = TEMPLATEUSER
    # Prefer tokens over passwords
    if TEMPLATETOKEN or TOKEN:
        if TEMPLATETOKEN:
            USER = USER + '/token'
            PASS = TEMPLATETOKEN
        else:
            USER = USER + '/token'
            PASS = TOKEN
    else:
        PASS = TEMPLATEPASS

    a = parse(request)

    payload = {
        "body": a['info'],
        "title": a['AlertName'],
        "type": "link",
        "url": a['url'],
    }

    # Defaults to Content-type: application/json
    # If changed you must specify the content-type manually
    headers = {
        'Content-type': 'application/json',
        'Accept': 'application/json'
    }
    if not headers:
        headers = None

    #########################
    # Fire and Forgot Systems
    #########################

    return callapi(TEMPLATEURL, 'post', json.dumps(payload), headers)
Esempio n. 32
0
def socialcast(ALERTID=None, NUMRESULTS=10, TEAM=None, I=None, X=None):
    """
    Create a post on Socialcast containing log events.
    Limited to `NUMRESULTS` (default 10) or 1MB.
    If `TEAM/I/X` is not passed, requires `SOCIALCASTURL` defined in the form `https://TEAM.socialcast.com/api/webhooks/IIIIIIIIII/XXXXXXXXXXX`
    For more information see https://socialcast.github.io/socialcast/apidoc/incoming_webhook.html
    """
    if X is not None:
        URL = 'https://' + TEAM + '.socialcast.com/api/webhooks/' + I + '/' + X
    if not SOCIALCASTURL or not 'socialcast.com/api/webhooks' in SOCIALCASTURL:
        return (
            "SOCIALCASTURL parameter must be set properly, please edit the shim!\n",
            500, None)
    else:
        URL = SOCIALCASTURL
    # Socialcast cares about the order of the information in the body
    # json.dumps() does not preserve the order so just use raw get_data()
    return callapi(URL, 'post', request.get_data())
Esempio n. 33
0
def slack(NUMRESULTS=10, ALERTID=None, T=None, B=None, X=None):
    """
    Consume messages, and send them to Slack as an Attachment object.
    Sends up to `NUMRESULTS` (default 10) events onward.
    If `T/B/X` is not passed, requires `SLACKURL` defined in the form `https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX`
    For more information, see https://api.slack.com/incoming-webhooks
    """
    # Prefer URL parameters to SLACKURL
    if X is not None:
        URL = 'https://hooks.slack.com/services/' + T + '/' + B + '/' + X
    elif not SLACKURL or not 'https://hooks.slack.com/services' in SLACKURL:
        return ("SLACKURL parameter must be set properly, please edit the shim!", 500, None)
    else:
        URL = SLACKURL

    a = parse(request)

    slack_attachments = []
    if (a['color'] == 'red'):
        color = 'danger'
    elif (a['color'] == 'yellow'):
        color = 'warning'
    else:
        color = 'info'
    payload = {
        "icon_url": a['icon'],
    }
    try:
        if ('AlertName' in a):
            slack_attachments.append({ "pretext": a['moreinfo'], })
            if ('Messages' in a):
                for message in a['Messages'][:NUMRESULTS]:
                    slack_attachments.append(slack_fields(color, message))
            if a['fields']:
                slack_attachments.append(slack_fields(color, a))
    except:
        logging.exception("Can't create new payload. Check code and try again.")
        raise

    payload.update({
        "username": a['hookName'],
        "attachments": slack_attachments
    })
    return callapi(URL, 'post', json.dumps(payload))
Esempio n. 34
0
def fetchResourceProperties(resourceId=None):
    headers = {
        'Content-type': 'application/json',
        'Accept': 'application/json'
    }
    alertURL = vropsURL + "api/resources/" + resourceId + "/properties"
    auth = (vropsUser, vropsPass)
    response = callapi(alertURL,
                       method='get',
                       payload=None,
                       headers=headers,
                       auth=auth,
                       check=VERIFY)
    rawProps = json.loads(response)

    props = {}
    for prop in rawProps['property']:
        props[prop["name"]] = prop["value"]
    return props
Esempio n. 35
0
def pagerduty(SERVICEKEY=None, ALERTID=None):
    """
    Create a new incident for the Pagerduty service identified by `SERVICEKEY` in the URL.
    Uses the https://v2.developer.pagerduty.com/v2/docs/trigger-events API directly.
    """
    if not PAGERDUTYURL:
        return (
            "PAGERDUTYURL parameter must be set properly, please edit the shim!",
            500, None)
    if not SERVICEKEY:
        return (
            "SERVICEKEY must be set in the URL (e.g. /endpoint/pagerduty/<SERVICEKEY>",
            500, None)

    # Retrieve fields in notification
    a = parse(request)

    payload = {
        "service_key":
        SERVICEKEY,
        "event_type":
        "trigger",
        "description":
        a['AlertName'],
        "details": {
            "notes": a['info'],
            "events": str(a['Messages']),
        },
        "contexts": [
            {
                "type": "link",
                "href": a['url'],
                "text": "View search results"
            },
            {
                "type": "link",
                "href": a['editurl'],
                "text": "View alert definition"
            },
        ]
    }
    return callapi(PAGERDUTYURL, 'post', json.dumps(payload))
Esempio n. 36
0
def template(ALERTID=None, TOKEN=None, EMAIL=None):
    """
    Information about this shim.
    Requires TEMPLATE* parameters to be defined.
    """
    if (not TEMPLATEURL or (not TEMPLATEUSER and not EMAIL) or (not TEMPLATEPASS and not TEMPLATETOKEN and not TOKEN)):
        return ("TEMPLATE* parameters must be set, please edit the shim!", 500, None)
    if not TEMPLATEUSER:
        USER = EMAIL
    else:
        USER = TEMPLATEUSER
    # Prefer tokens over passwords
    if TEMPLATETOKEN or TOKEN:
        if TEMPLATETOKEN:
            USER = USER + '/token'
            PASS = TEMPLATETOKEN
        else:
            USER = USER + '/token'
            PASS = TOKEN
    else:
        PASS = TEMPLATEPASS

    a = parse(request)

    payload = {
        "body": a['info'],
        "title": a['AlertName'],
        "type": "link",
        "url": a['url'],
    }

    # Defaults to Content-type: application/json
    # If changed you must specify the content-type manually
    headers = {'Content-type': 'application/json', 'Accept': 'application/json'}
    if not headers:
        headers = None

    #########################
    # Fire and Forgot Systems
    #########################

    return callapi(TEMPLATEURL, 'post', json.dumps(payload), headers)
Esempio n. 37
0
def travisci(ALERTID=None, TOKEN=None, REPO=None, BRANCH=None):
    """
    If called, run a Travis CI job.
    If `TOKEN`, `REPO`, and/or `BRANCH` are not passed then the must be defined
    For more information, see https://docs.travis-ci.com/user/triggering-builds
    """
    if (not TRAVISCIURL or (not TRAVISCITOKEN and not TOKEN)
            or (not TRAVISCIREPO and not REPO)
            or (not TRAVISCIBRANCH and not BRANCH)):
        return ("TRAVISCI* parameters must be set, please edit the shim!", 500,
                None)
    # Prefer tokens over passwords
    if not TOKEN:
        TOKEN = TRAVISCITOKEN
    if not REPO:
        REPO = TRAVISCIREPO
    if not BRANCH:
        BRANCH = TRAVISCIBRANCH

    a = parse(request)

    payload = {
        "request": {
            "message": "Override the commit message: this is an api request",
            "branch": BRANCH,
            "token": TOKEN
        }
    }

    # Defaults to Content-type: application/json
    # If changed you must specify the content-type manually
    headers = {
        'Content-type': 'application/json',
        'Accept': 'application/json',
        'Accept': 'application/vnd.travis-ci.2+json',
        'Client': 'LogInsight/1.0',
        'Authorization': 'token ' + TOKEN,
        'Travis-API-Version': '3'
    }

    return callapi(TRAVISCIURL + REPO + '/requests', 'post',
                   json.dumps(payload), headers)
Esempio n. 38
0
def opsgenie(APIKEY=None, ALERTID=None):
    """
    Create a new incident for the opsgenie service identified by `APIKEY` in the URL.
    Uses https://docs.opsgenie.com/docs/alert-api.
    """
    if not OPSGENIEURL:
        return ("OPSGENIEURL parameter must be set properly, please edit the shim!", 500, None)
    if not APIKEY:
        return ("APIKEY must be set in the URL (e.g. /endpoint/opsgenie/<APIKEY>", 500, None)
    HEADERS = {"Content-type": "application/json", "Authorization": "GenieKey " + APIKEY}

    # Retrieve fields in notification
    a = parse(request)

    payload = {
        "alias": a['AlertName'],
        "message": a['AlertName'],
        "description": a['moreinfo']
    }
    return callapi(OPSGENIEURL, 'post', json.dumps(payload), HEADERS)
Esempio n. 39
0
def travisci(ALERTID=None, TOKEN=None, REPO=None, BRANCH=None):
    """
    If called, run a Travis CI job.
    If `TOKEN`, `REPO`, and/or `BRANCH` are not passed then the must be defined
    For more information, see https://docs.travis-ci.com/user/triggering-builds
    """
    if (not TRAVISCIURL or (not TRAVISCITOKEN and not TOKEN) or (not TRAVISCIREPO and not REPO) or (not TRAVISCIBRANCH and not BRANCH)):
        return ("TRAVISCI* parameters must be set, please edit the shim!", 500, None)
    # Prefer tokens over passwords
    if not TOKEN:
        TOKEN = TRAVISCITOKEN
    if not REPO:
        REPO = TRAVISCIREPO
    if not BRANCH:
        BRANCH = TRAVISCIBRANCH

    a = parse(request)

    payload = {
        "request": {
            "message": "Override the commit message: this is an api request",
            "branch": BRANCH,
            "token": TOKEN
        }
    }

    # Defaults to Content-type: application/json
    # If changed you must specify the content-type manually
    headers = {
        'Content-type': 'application/json',
        'Accept': 'application/json',
        'Accept': 'application/vnd.travis-ci.2+json',
        'Client': 'LogInsight/1.0',
        'Authorization': 'token ' + TOKEN,
        'Travis-API-Version': '3'
    }

    return callapi(TRAVISCIURL + REPO + '/requests', 'post', json.dumps(payload), headers)
Esempio n. 40
0
def wxteams(HOOKID=None, RESOURCEID=None):
    """
    Send messages to Spark/Webex Teams. If HOOKID is not present, requires WXTEAMS defined as 'https://api.ciscospark.com/v1/webooks/incoming/<HOOKID>
    """
    # Prefer URL parameters to WXTEAMS
    if HOOKID is not None:
        URL = 'https://api.ciscospark.com/v1/webhooks/incoming/' + HOOKID
    elif not WXTEAMS or not 'https://api.ciscospark.com/v1/webhooks/incoming' in WXTEAMS:
        return (
            "WXTEAMS parameter must be set properly, please edit the shim!",
            500, None)
    else:
        URL = WXTEAMS

    a = parse(request)

    try:
        if ('alertId' in a):
            timezone = pytz.timezone('America/Chicago')
            d = datetime.fromtimestamp(int(a['startDate'] /
                                           1000.0)).replace(tzinfo=timezone)
            alertTime = d.strftime('%Y-%m-%d %H:%M:%S')

            message = "Resource Name: {resourceName}\n" \
                      "Timestamp: {alertTime}\n" \
                      "Status: {status}\n" \
                      "Info: {info}".format(resourceName=a['resourceName'],
                                            alertTime=alertTime,
                                            status=a['status'],
                                            info=a['info']
                                            )
            payload = {"text": message}
    except:
        logging.exception(
            "Can't create new payload. Check code and try again.")
        raise

    return callapi(URL, 'post', json.dumps(payload))
Esempio n. 41
0
def bigpanda(TOKEN=None, APPKEY=None, ALERTID=None):
    """
    Create a new incident for the bigpanda service identified by `APIKEY` in the URL.
    Uses https://docs.bigpanda.io/reference#alerts.
    """
    if not BIGPANDAURL:
        return ("BIGPANDAURL parameter must be set properly, please edit the shim!", 500, None)
    if not TOKEN:
        return ("TOKEN must be set in the URL (e.g. /endpoint/bigpanda/<TOKEN>/<APPKEY>", 500, None)
    if not APPKEY:
        return ("APPKEY must be set in the URL (e.g. /endpoint/bigpanda/<TOKEN>/<APPKEY>", 500, None)
    HEADERS = {"Accept": "application/json", "Content-Type": "application/json", "Authorization": "Bearer " + TOKEN}

    # Retrieve fields in notification
    a = parse(request)

    payload = {
        "app_key": APPKEY,
        "host": "Webhook Shim",
        "check": a['AlertName'],
        "description": a['moreinfo']
    }
    return callapi(BIGPANDAURL, 'post', json.dumps(payload), HEADERS)
Esempio n. 42
0
def pushbullet(ALERTID=None, TOKEN=None):
    """
    Send a `link` notification to all devices on pushbullet with a link back to the alert's query.
    If `TOKEN` is not passed, requires `PUSHBULLETTOKEN` defined, see https://www.pushbullet.com/#settings/account
    """
    if not PUSHBULLETURL:
        return ("PUSHBULLET parameter must be set, please edit the shim!", 500, None)
    if (TOKEN is not None):
        PUSHBULLETTOKEN = TOKEN
    if not PUSHBULLETTOKEN:
        return ("PUSHBULLETTOKEN parameter must be set, please edit the shim!", 500, None)

    a = parse(request)

    payload = {
        "body": a['info'],
        "title": a['AlertName'],
        "type": "link",
        "url": a['url'],
    }

    headers = {'Content-type': 'application/json', 'Access-Token': PUSHBULLETTOKEN}

    return callapi(PUSHBULLETURL, 'post', json.dumps(payload), headers)
def vro(WORKFLOWID=None, TOKEN=None, HOK=None, ALERTID=None):
    """
    Start a vRealize Orchestrator workflow, passing the entire JSON alert as a base64-encoded string.
    The `WORKFLOWID` and optionally `TOKEN` is passed in the webhook URL.
    The workflow is responsible for parsing base64 -> json -> messages
    """
    bauth = request.authorization
    if bauth is not None:
        global VROUSER
        global VROPASS
        VROUSER = bauth.username
        VROPASS = bauth.password

    if not WORKFLOWID:
        return ("WORKFLOWID must be set in the URL (e.g. /endpoint/vro/<WORKFLOWID>", 500, None)
    if not re.match('[a-z0-9-]+', WORKFLOWID, flags=re.IGNORECASE):
        return ("WORKFLOWID must consist of alphanumeric and dash characters only", 500, None)
    if not VROHOSTNAME:
	return("VROHOSTNAME parameter is not net, please edit the shim!", 500, None)
    if not USENETRC and (not VROUSER and not VROPASS and not VROTOKEN and not TOKEN and not VROHOK and not HOK):
        return ("VRO* authentication parameters must be set, please edit the shim!", 500, None)

    if TOKEN is None and VROTOKEN:
        TOKEN = VROTOKEN
    elif HOK is None and VROHOK:
        HOK = VROHOK

    AUTH = None
    HEADERS = None
    if TOKEN is not None:
        HEADERS = {"Authorization": TOKEN}
    elif HOK is not None:
        HEADERS = {"Authorization": "Bearer " + HOK}
    elif not USENETRC:
        AUTH = (VROUSER, VROPASS)

    if ALERTID is None: # LI payload
        a = parse(request)

        payload = {
            "parameters": [
                {
                    "value": {
                        "string": {
                            "value": base64.b64encode(request.get_data())
                        }
                    },
                    "type": "string",
                    "name": "messages",
                    "scope": "local"
                },
                {
                    "value": {
                        "string": {
                            "value": a['AlertName']
                        }
                    },
                    "type": "string",
                    "name": "alertName",
                    "scope": "local"
                },
                {
                    "value": {
                        "number": {
                            "value": a['NumHits']
                        }
                    },
                    "type": "number",
                    "name": "hitCount",
                    "scope": "local"
                }
            ]
        }
    else: # vROps payload
        # If you would like, you can parse the payload from vROps.  However, it is
        # probably easier to just pass the ALERTID as workflow input to a wrapper and
        # look up the alert from vRO.  This gets around the problem of having to encode
        # the alert payload for vRO.
        # a = parse(request)

        payload = {
            "parameters": [
                {
                    "value": {
                        "string": {
                            "value": ALERTID
                        }
                    },
                    "type": "string",
                    "name": "alertId",
                    "scope": "local"
                }
            ]
        }
    return callapi("https://" + VROHOSTNAME + "/vco/api/workflows/" + WORKFLOWID + "/executions", 'post', json.dumps(payload), HEADERS, AUTH, VERIFY)
Esempio n. 44
0
def groove(ALERTID=None, TOKEN=None, FROM=None, TO=None):
    """
    Create a new ticket for every incoming webhook.
    Groove does not support searching for open tickets by subject today.
    Requires GROOVE* parameters to be defined.
    """
    if not GROOVEURL or (not GROOVEFROM and not FROM) or (not GROOVETO
                                                          and not TO):
        return ("GROOVE* parameters must be set, please edit the shim!", 500,
                None)
    if TOKEN is None:
        return (
            "TOKEN must be passed in the URL, please edit the incoming webhook!",
            500, None)
    if GROOVEFROM and not FROM:
        FROM = GROOVEFROM
    if GROOVETO and not TO:
        TO = GROOVETO

    a = parse(request)

    headers = {
        'Content-type': 'application/json',
        'Authorization': 'Bearer ' + TOKEN
    }

    # Unfortunately, the Groove API does not support searching for open tickets by subject today
    # https://www.groovehq.com/docs/tickets#finding-one-ticket
    # As a result, every incoming webhook will result in a new ticket
    # Commented sections has been wired for when the Groove API is updated to support the use case

    ## Get the list of open incidents that contain the AlertName from the incoming webhook
    # payload = {
    #     "state": "notstarted,opened,pending",
    #     "subject": a['AlertName']
    # }
    # incident = callapi(GROOVEURL + '/tickets', 'get', payload, headers)
    #
    # try:
    #   i = json.loads(incident)
    # except:
    #   return incident

    # try: # Determine if there is an open incident already
    #     if i['tickets'][0]['number'] is not None:
    #         # Option 1: Do nothing
    #         #logging.info('Nothing to do, exiting.')
    #         #return ("OK", 200, None)

    #         # Option 2: Add a new message
    #         payload = { 'body': a['moreinfo'] }
    #         return callapi(GROOVEURL + '/tickets/' + str(i['tickets'][0]['number']) + '/messages', 'put', json.dumps(payload), headers)
    # except: # If no open incident then open one
    payload = {
        "ticket": {
            "body": a['moreinfo'],
            "from": FROM,
            "to": TO,
            "subject": a['AlertName'],
            "tags": ["loginsight"]
        }
    }
    return callapi(GROOVEURL + '/tickets', 'post', json.dumps(payload),
                   headers)
Esempio n. 45
0
def moogsoft(ALERTID=None):
    """
    Information about this shim.
    Requires moogsoft* parameters to be defined.
    """

    if (not moogsoftURL or (not moogsoftUSER) or (not moogsoftPASS)
            or (not vropsURL) or (not vropsUser) or (not vropsPass)):
        return (
            "moogsoft* and vrops* parameters must be set, please edit the shim!",
            500, None)

    a = parse(request)

    ########################################
    #Map vROps crticiality to moog sev here
    ########################################
    sevMap = {
        "ALERT_CRITICALITY_LEVEL_CRITICAL": 5,
        "ALERT_CRITICALITY_LEVEL_IMMEDIATE": 4,
        "ALERT_CRITICALITY_LEVEL_WARNING": 3,
        "ALERT_CRITICALITY_LEVEL_INFO": 2
    }
    link = vropsURL + "/ui/index.action#/object/" + a[
        'resourceId'] + "/alertsAndSymptoms/alerts/" + ALERTID
    recommendation = recommendations(a['alertId'])
    resourceProperties = fetchResourceProperties(a['resourceId'])

    payload = {
        "signature": ALERTID,
        "source_id": a['resourceId'],
        "external_id": ALERTID,
        "manager": a['hookName'],
        "source": a['resourceName'] if
        (a['resourceName'] != "") else "undefined",
        "class": a['subType'],
        "agent": a['adapterKind'],
        "agent_location": "",
        "type": a['type'] + "::" + a['subType'],
        "severity": sevMap[a['criticality']] if
        (a['status'] != 'CANCELED') else 0,
        "description": a['AlertName'],
        "agent_time": a['updateDate'] / 1000,
        "recommendation": recommendation,
        "resource_properties": resourceProperties,
        "link": link
    }

    # Defaults to Content-type: application/json
    # If changed you must specify the content-type manually
    headers = {
        'Content-type': 'application/json',
        'Accept': 'application/json'
    }
    if not headers:
        headers = None

    return callapi(moogsoftURL,
                   'post',
                   json.dumps(payload),
                   headers,
                   check=VERIFY)
Esempio n. 46
0
def bugzilla(ALERTID=None, TOKEN=None, PRODUCT=None, COMPONENT=None, VERSION=None):
    """
    Create a new bug for every incoming webhook that does not already have an open bug.
    If an bug is already open, add a new comment to the open bug.
    Uniqueness is determined by the incoming webhook alert name combined with bugzilla product and component.
    Requires BUGZILLA* parameters to be defined.
    You can pass an authentication token in the URL. For basic auth, pass `-` as the token.
    """
    if (not BUGZILLAURL or
        ((not BUGZILLAUSER or not BUGZILLAPASS) and (not TOKEN or TOKEN == '-')) or
        ((not BUGZILLAPRODUCT or not BUGZILLACOMPONENT or not BUGZILLAVERSION) and not VERSION)):
            logging.debug("URL: %s\nUSER: %s\nPASS: %s\nTOKEN: %s\nPRODUCT: %s / %s\nCOMPONENT: %s / %s\nVERSION: %s / %s" % (BUGZILLAURL, BUGZILLAUSER, BUGZILLAPASS, TOKEN, BUGZILLAPRODUCT, PRODUCT, BUGZILLACOMPONENT, COMPONENT, BUGZILLAVERSION, VERSION))
            return ("BUGZILLA* parameters must be set, please edit the shim!", 500, None)

    a = parse(request)

    if TOKEN and TOKEN != '-':
        auth = 'api_key=' + TOKEN
    else:
        auth = 'login='******'&password='******'Content-type': 'application/json', 'Accept': 'application/json'}

    # Get the list of open bugs that contain the AlertName from the incoming webhook
    bug = callapi(BUGZILLAURL + '/rest/bug?' + auth + '&product=' + PRODUCT + '&component=' + COMPONENT + '&summary=' + a['AlertName'], 'get', None, headers, None, VERIFY)
    try:
        i = json.loads(bug)
    except:
        return bug

    try: # Determine if there is an open bug already
        if i['bugs'][0]['id'] is not None:
            # Option 1: Do nothing
            #logging.info('Nothing to do, exiting.')
            #return ("OK", 200, None)

            # Option 2: Add a new comment
            payload = { 'comment': { 'body': a['moreinfo'] } }
            return callapi(BUGZILLAURL + '/rest/bug/' + str(i['bugs'][0]['id']) + '?' + auth, 'put', json.dumps(payload), headers, None, VERIFY)
    except: # If no open bug then open one
        payload = {
            "product" : PRODUCT,
            "component" : COMPONENT,
            "version" : VERSION,
            "summary" : a['AlertName'],
            "description": a['info'],
        }
        # op_sys and rep_platform may not be needed, but are to test on landfill
        if "landfill.bugzilla.org" in BUGZILLAURL:
            payload.update({
                "op_sys": "All",
                "rep_platform": "All",
            })
        return callapi(BUGZILLAURL + '/rest/bug?' + auth, 'post', json.dumps(payload), headers, None, VERIFY)
Esempio n. 47
0
def hipchat(NUMRESULTS=1,
            ALERTID=None,
            TEAM=None,
            ROOMNUM=None,
            AUTHTOKEN=None):
    """
    Consume messages, and send them to HipChat as an Attachment object.
    If `TEAM/ROOMNUM/AUTHOKEN` is not passed, requires `HIPCHATURL` defined in the form `https://TEAM.hipchat.com/v2/room/0000000/notification?auth_token=XXXXXXXXXXXXXXXXXXXXXXXXXXX`
    For more information, see https://www.hipchat.com/docs/apiv2/method/send_room_notification
    """
    # Prefer URL parameters to HIPCHATURL
    if AUTHTOKEN is not None:
        URL = 'https://' + TEAM + '.hipchat.com/v2/room/' + ROOMNUM + '/notification?auth_token=' + AUTHTOKEN
    elif not HIPCHATURL or not 'hipchat.com/v2/room' in HIPCHATURL:
        return (
            "HIPCHATURL parameter must be set properly, please edit the shim!",
            500, None)
    else:
        URL = HIPCHATURL

    a = parse(request)

    hipchat_attachments = []
    attachment_prefix = {
        "style": "application",
        "format": "medium",
        "id": "1",
    }
    attachment = {
        "icon": {
            "url": a['icon']
        },
    }
    try:
        # Log Insight
        if ('Messages' in a):
            for message in a['Messages'][:NUMRESULTS]:
                attachment.update(attachment_prefix)
                attachment.update({
                    "title": a['AlertName'],
                })
                if (a['url'] != ""):
                    attachment.update({
                        "url": a['url'],
                        "activity": {
                            "html": a['moreinfo'],
                        }
                    })
                elif (message['text'] is not None):
                    attachment.update(
                        {"activity": {
                            "html": message['text'],
                        }})
                if (message['fields'] is not None):
                    message['fields'] = message['fields'] + a['fields']
                    attachment.update({
                        "attributes": [
                            {  # start of dict comprehension
                                "label": f['name'],
                                "value": {
                                    "label": f['content']
                                }
                            } for f in message['fields']
                            if not f['name'].startswith('__')
                        ],
                    })
                hipchat_attachments.append(attachment)
                attachment = {}  # only attach the icon to the first card
        # Additional information (non-product specific)
        elif (a['fields'] is not None):
            attachment.update(attachment_prefix)
            attachment.update({
                "title":
                a['AlertName'],
                "activity": {
                    "html": a['moreinfo'],
                },
                "attributes": [
                    {  # start of dict comprehension
                        "label": f['name'],
                        "value": {
                            "label": f['content']
                        }
                    } for f in a['fields']
                ],
            })
            hipchat_attachments.append(attachment)
    except:
        logging.exception(
            "Can't create new payload. Check code and try again.")
        raise
    if 'Messages' in a and not a['Messages']:  # If a test alert
        attachment.update(attachment_prefix)
        attachment.update({
            "title":
            "This is a test webhook alert",
            "attributes": [{  # start of dict comprehension
                "label": "Test",
                "value": {
                    "label": "It works!"
                }
            }],
        })
        hipchat_attachments.append(attachment)

    payload = {
        "from": a['hookName'],
        "color": a['color'] if
        ('color' in a and a['color'] is not None) else "gray",
        "message_format": "text",
        "message": a['moreinfo'],
        "notify": 'true',
        "card": hipchat_attachments.pop(0),
    }
    return callapi(URL, 'post', json.dumps(payload))
Esempio n. 48
0
def msteams(NUMRESULTS=10, ALERTID=None):
    """
    Posts a message to a Microsoft Teams channel. Set TEAMSURL to the incoming
    webhook URL provided by Teams. To create a Teams webhook see:
    http://aka.ms/o365-connectors
    """

    if not TEAMSURL:
        return ("The TEAMSURL parameter must be set, please edit the shim!",
                500, None)

    a = parse(request)

    teams_attachments = [{
        "activityImage":
        a['icon'],
        "activityTitle":
        a['AlertName'] if 'AlertName' in a else "Alert details",
        "activitySubtitle":
        "[Link to Alert](" + a['url'] + ")" if a['url'] else "",
    }]

    try:
        if ('AlertName' in a):
            if ('Messages' in a):
                for message in a['Messages'][:NUMRESULTS]:
                    teams_attachments.append(teams_fields(message))
            if (a['fields'] is not None):
                teams_attachments.append(teams_fields(a))
    except:
        logging.exception(
            "Can't create new payload. Check code and try again.")
        raise

    if (a['color'] == 'red'):
        color = 'CC0000'
    elif (a['color'] == 'yellow'):
        color = 'FFCC00'
    elif (a['color'] == 'green'):
        color = '009000'
    else:
        color = '0075FF'

    payload = {
        "@type": "MessageCard",
        "@context": "http://schema.org/extensions",
        "themeColor": color,
        "summary": "Message from " + a['hookName'],
        "sections": teams_attachments
    }

    # Defaults to Content-type: application/json
    # If changed you must specify the content-type manually
    headers = {
        'Content-type': 'application/json',
        'Accept': 'application/json'
    }
    if not headers:
        headers = None

    return callapi(TEAMSURL, 'post', json.dumps(payload), headers)
Esempio n. 49
0
def hipchat(NUMRESULTS=1, ALERTID=None, TEAM=None, ROOMNUM=None, AUTHTOKEN=None):
    """
    Consume messages, and send them to HipChat as an Attachment object.
    If `TEAM/ROOMNUM/AUTHOKEN` is not passed, requires `HIPCHATURL` defined in the form `https://TEAM.hipchat.com/v2/room/0000000/notification?auth_token=XXXXXXXXXXXXXXXXXXXXXXXXXXX`
    For more information, see https://www.hipchat.com/docs/apiv2/method/send_room_notification
    """
    # Prefer URL parameters to HIPCHATURL
    if AUTHTOKEN is not None:
        URL = 'https://' + TEAM + '.hipchat.com/v2/room/' + ROOMNUM + '/notification?auth_token=' + AUTHTOKEN
    elif not HIPCHATURL or not 'hipchat.com/v2/room' in HIPCHATURL:
        return ("HIPCHATURL parameter must be set properly, please edit the shim!", 500, None)
    else:
        URL = HIPCHATURL

    a = parse(request)

    hipchat_attachments = []
    attachment_prefix = {
        "style": "application",
        "format": "medium",
        "id": "1",
    }
    attachment = {
        "icon": { "url": a['icon'] },
    }
    try:
        # Log Insight
        if ('Messages' in a):
            for message in a['Messages'][:NUMRESULTS]:
                attachment.update(attachment_prefix)
                attachment.update({
                    "title": a['AlertName'],
                })
                if (a['url'] != ""):
                    attachment.update({
                        "url": a['url'],
                        "activity": {
                            "html": a['moreinfo'],
                        }
                    })
                elif (message['text'] is not None):
                    attachment.update({
                        "activity": {
                            "html": message['text'],
                        }
                    })
                if (message['fields'] is not None):
                    message['fields'] = message['fields'] + a['fields']
                    attachment.update({
                        "attributes": [{  # start of dict comprehension
                            "label": f['name'],
                            "value": { "label": f['content'] }
                        } for f in message['fields'] if not f['name'].startswith('__')],
                    })
                hipchat_attachments.append(attachment)
                attachment = {} # only attach the icon to the first card
        # Additional information (non-product specific)
        elif (a['fields'] is not None):
            attachment.update(attachment_prefix)
            attachment.update({
                "title": a['AlertName'],
                "activity": {
                    "html": a['moreinfo'],
                },
                "attributes": [{  # start of dict comprehension
                    "label": f['name'],
                    "value": { "label": f['content'] }
                } for f in a['fields']],
            })
            hipchat_attachments.append(attachment)
    except:
        logging.exception("Can't create new payload. Check code and try again.")
        raise
    if 'Messages' in a and not a['Messages']: # If a test alert
        attachment.update(attachment_prefix)
        attachment.update({
            "title": "This is a test webhook alert",
            "attributes": [
                {  # start of dict comprehension
                    "label": "Test",
                    "value": { "label": "It works!" }
                }
            ],
        })
        hipchat_attachments.append(attachment)

    payload = {
        "from": a['hookName'],
        "color": a['color'] if ('color' in a and a['color'] is not None) else "gray",
        "message_format": "text",
        "message": a['moreinfo'],
        "notify": 'true',
        "card": hipchat_attachments.pop(0),
    }
    return callapi(URL, 'post', json.dumps(payload))
Esempio n. 50
0
def vro(WORKFLOWID=None, TOKEN=None, HOK=None, ALERTID=None):
    """
    Start a vRealize Orchestrator workflow, passing the entire JSON alert as a base64-encoded string.
    The `WORKFLOWID` and optionally `TOKEN` is passed in the webhook URL.
    The workflow is responsible for parsing base64 -> json -> messages
    """
    if not WORKFLOWID:
        return (
            "WORKFLOWID must be set in the URL (e.g. /endpoint/vro/<WORKFLOWID>",
            500, None)
    if not re.match('[a-z0-9-]+', WORKFLOWID, flags=re.IGNORECASE):
        return (
            "WORKFLOWID must consist of alphanumeric and dash characters only",
            500, None)
    if not VROHOSTNAME:
        return ("VROHOSTNAME parameter is not net, please edit the shim!", 500,
                None)
    if not USENETRC and (not VROUSER and not VROPASS and not VROTOKEN
                         and not TOKEN and not VROHOK and not HOK):
        return (
            "VRO* authentication parameters must be set, please edit the shim!",
            500, None)

    if TOKEN is None and VROTOKEN:
        TOKEN = VROTOKEN
    elif HOK is None and VROHOK:
        HOK = VROHOK

    AUTH = None
    HEADERS = None
    if TOKEN is not None:
        HEADERS = {"Authorization": TOKEN}
    elif HOK is not None:
        HEADERS = {"Authorization": "Bearer " + HOK}
    elif not USENETRC:
        AUTH = (VROUSER, VROPASS)

    if ALERTID is None:  # LI payload
        a = parse(request)

        payload = {
            "parameters": [{
                "value": {
                    "string": {
                        "value": base64.b64encode(request.get_data())
                    }
                },
                "type": "string",
                "name": "messages",
                "scope": "local"
            }, {
                "value": {
                    "string": {
                        "value": a['AlertName']
                    }
                },
                "type": "string",
                "name": "alertName",
                "scope": "local"
            }, {
                "value": {
                    "number": {
                        "value": a['NumHits']
                    }
                },
                "type": "number",
                "name": "hitCount",
                "scope": "local"
            }]
        }
    else:  # vROps payload
        # If you would like, you can parse the payload from vROps.  However, it is
        # probably easier to just pass the ALERTID as workflow input to a wrapper and
        # look up the alert from vRO.  This gets around the problem of having to encode
        # the alert payload for vRO.
        # a = parse(request)

        payload = {
            "parameters": [{
                "value": {
                    "string": {
                        "value": ALERTID
                    }
                },
                "type": "string",
                "name": "alertId",
                "scope": "local"
            }]
        }
    return callapi(
        "https://" + VROHOSTNAME + "/vco/api/workflows/" + WORKFLOWID +
        "/executions", 'post', json.dumps(payload), HEADERS, AUTH, VERIFY)
Esempio n. 51
0
def bugzilla(ALERTID=None,
             TOKEN=None,
             PRODUCT=None,
             COMPONENT=None,
             VERSION=None):
    """
    Create a new bug for every incoming webhook that does not already have an open bug.
    If an bug is already open, add a new comment to the open bug.
    Uniqueness is determined by the incoming webhook alert name combined with bugzilla product and component.
    Requires BUGZILLA* parameters to be defined.
    You can pass an authentication token in the URL. For basic auth, pass `-` as the token.
    """
    bauth = request.authorization
    if bauth is not None:
        global BUGZILLAUSER
        global BUGZILLAPASS
        BUGZILLAUSER = bauth.username
        BUGZILLAPASS = bauth.password

    if (not BUGZILLAURL or ((not BUGZILLAUSER or not BUGZILLAPASS) and
                            (not TOKEN or TOKEN == '-')) or
        ((not BUGZILLAPRODUCT or not BUGZILLACOMPONENT or not BUGZILLAVERSION)
         and not VERSION)):
        logging.debug(
            "URL: %s\nUSER: %s\nPASS: %s\nTOKEN: %s\nPRODUCT: %s / %s\nCOMPONENT: %s / %s\nVERSION: %s / %s"
            %
            (BUGZILLAURL, BUGZILLAUSER, BUGZILLAPASS, TOKEN, BUGZILLAPRODUCT,
             PRODUCT, BUGZILLACOMPONENT, COMPONENT, BUGZILLAVERSION, VERSION))
        return ("BUGZILLA* parameters must be set, please edit the shim!", 500,
                None)

    a = parse(request)

    if TOKEN and TOKEN != '-':
        auth = 'api_key=' + TOKEN
    else:
        auth = 'login='******'&password='******'Content-type': 'application/json',
        'Accept': 'application/json'
    }

    # Get the list of open bugs that contain the AlertName from the incoming webhook
    bug = callapi(
        BUGZILLAURL + '/rest/bug?' + auth + '&product=' + PRODUCT +
        '&component=' + COMPONENT + '&summary=' + a['AlertName'], 'get', None,
        headers, None, VERIFY)
    try:
        i = json.loads(bug)
    except:
        return bug

    try:  # Determine if there is an open bug already
        if i['bugs'][0]['id'] is not None:
            # Option 1: Do nothing
            #logging.info('Nothing to do, exiting.')
            #return ("OK", 200, None)

            # Option 2: Add a new comment
            payload = {'comment': {'body': a['moreinfo']}}
            return callapi(
                BUGZILLAURL + '/rest/bug/' + str(i['bugs'][0]['id']) + '?' +
                auth, 'put', json.dumps(payload), headers, None, VERIFY)
    except:  # If no open bug then open one
        payload = {
            "product": PRODUCT,
            "component": COMPONENT,
            "version": VERSION,
            "summary": a['AlertName'],
            "description": a['info'],
        }
        # op_sys and rep_platform may not be needed, but are to test on landfill
        if "landfill.bugzilla.org" in BUGZILLAURL:
            payload.update({
                "op_sys": "All",
                "rep_platform": "All",
            })
        return callapi(BUGZILLAURL + '/rest/bug?' + auth, 'post',
                       json.dumps(payload), headers, None, VERIFY)
Esempio n. 52
0
def zendesk(ALERTID=None, EMAIL=None, TOKEN=None):
    """
    Create a new incident for every incoming webhook that does not already have an open incident.
    If an incident is already open, add a new comment to the open alert.
    Uniqueness is determined by the incoming webhook alert name.
    Requires ZENDESK* parameters to be defined.
    """
    bauth = request.authorization
    if bauth is not None:
        global ZENDESKUSER
        global ZENDESKPASS
        ZENDESKUSER = bauth.username
        ZENDESKPASS = bauth.password

    if (not ZENDESKURL or (not ZENDESKUSER and not EMAIL)
            or (not ZENDESKPASS and not ZENDESKTOKEN and not TOKEN)):
        return ("ZENDESK* parameters must be set, please edit the shim!", 500,
                None)
    if not ZENDESKUSER:
        USER = EMAIL
    else:
        USER = ZENDESKUSER

    # Prefer tokens over passwords
    if ZENDESKTOKEN or TOKEN:
        if ZENDESKTOKEN:
            USER = USER + '/token'
            PASS = ZENDESKTOKEN
        else:
            USER = USER + '/token'
            PASS = TOKEN
    else:
        PASS = ZENDESKPASS

    headers = {
        'Content-type': 'application/json',
        'Accept': 'application/json'
    }
    a = parse(request)

    # Get the list of open incidents that contain the AlertName from the incoming webhook
    incident = callapi(
        ZENDESKURL +
        '/api/v2/search.json?query=type:ticket status:open subject:"' +
        a['AlertName'] + '"', 'get', None, headers, (USER, PASS))
    i = json.loads(incident)

    try:  # Determine if there is an open incident already
        if i['results'][0]['id'] is not None:
            # Option 1: Do nothing
            #logging.info('Nothing to do, exiting.')
            #return ("OK", 200, None)

            # Option 2: Add a new comment
            # Limited to 30 updates per 10 minutes (https://developer.zendesk.com/rest_api/docs/core/introduction)
            payload = {'ticket': {'comment': {'body': a['moreinfo']}}}
            return callapi(
                ZENDESKURL + '/api/v2/tickets/' + str(i['results'][0]['id']) +
                '.json', 'put', json.dumps(payload), headers, (USER, PASS))
    except:  # If no open incident then open one
        payload = {
            "ticket": {
                #"requester": {
                #    "name": "Log Insight",
                #    "email": USER
                #},
                "subject": a['AlertName'],
                "comment": {
                    "body": a['moreinfo'],
                },
                "type": 'incident',
                "tags": ["loginsight"]
            }
        }
        return callapi(ZENDESKURL + '/api/v2/tickets.json', 'post',
                       json.dumps(payload), headers, (USER, PASS))
def test_bugzilla_e2e():
    url = URL + '/rest/bug?api_key=' + TOKEN + '&product=' + PRODUCT + '&component=' + COMPONENT + '&summary=' + json.loads(payload)['AlertName']
    id = json.loads(loginsightwebhookdemo.callapi(url, 'get'))['bugs'][0]['id']
    url = URL + '/rest/bug/' + str(id) + '/comment?api_key=' + TOKEN + '&product=' + PRODUCT + '&component=' + COMPONENT + '&summary=' + json.loads(payload)['AlertName']
    assert json.loads(loginsightwebhookdemo.callapi(url, 'get'))['bugs'][str(id)]['comments'][1]['text'].startswith('Alert Name: ')