logo

NJP

Google Cloud Operations monitoring notifications in Event Management

Import · Sep 25, 2020 · article

My colleague, @Ryan Balcom, and I have been plugging away on a side project to get Google Cloud Ops monitoring notifications into Event Management in ServiceNow and wanted to share the results here in case others are doing the same.

We used a Listener Transform Script to receive Google's JSON and map it to the Event record in ServiceNow.

This is definitely work-in-progress, needs further work to meet specific customer needs, and is not officially supported. It should give a head start on getting this set up though.

Some prerequisites:

  • The service account in ServiceNow used by Google to connect to the instance should have "Web service access only" checked, and must have the "evt_mgmt_integration" role assigned.
  • The url for Google's webhook to post to is https://{Instance-name}.service-now.com/api/global/em/inbound_event?source={URL_parameter_value}
  • * URL_parameter_value comes from the "URL parameter value" field on the Listener Transform Script record.
    • Note: for customers hosted in GCC, the URL is slightly different: https://{Instance-name}.servicenowservices.com/api/global/em/inbound_event?source={URL_parameter_value}

We configured the Listener Transform Script as follows:

  • Name: Google Monitoring Test Events Instance
  • Type: Instance (you could use a MID server to receive events as well, but we didn't for testing)
  • URL parameter value: googleJson (this can be anything you want, it forms the end of the URL referenced above)
  • Header name: generic-header
  • Header value: true

Script:

(function process( /*RESTAPIRequest*/ request, body) {
    /*Function that receives a JSON object, adding all its fields to the Additional information object. The field name is a concatenation of the field key and the parent field key if it exists.*/
    function updateAdditionalInfo(event, field, jsonObject, additionalInfo) {
        for (var key in jsonObject) {
            var newKey = key;
            if (field != "") {
                newKey = field + '_' + key;
            }

            /* SAMPLE PAYLOAD FROM GOOGLE
               REFERENCED HERE https://cloud.google.com/monitoring/support/notification-options

              {
                "incident": {
                  "incident_id": "f2e08c333dc64cb09f75eaab355393bz",
                  "resource_id": "i-4a266a2d",
                  "resource_name": "webserver-85",
                  "state": "open",
                  "started_at": 1385085727,
                  "ended_at": null,
                  "policy_name": "Webserver Health",
                  "condition_name": "CPU usage",
                  "url": "https://console.cloud.google.com/monitoring/alerting/incidents?project=PROJECT_ID",
                  "summary": "CPU for webserver-85 is above the threshold of 1% with a value of 28.5%"
                },
                "version": 1.1
              }
             */

            // PERFORM YOUR SPECIFIC TRANSFORMS HERE

            /* Unclear if this should be mapped to message_key
            if(key == "incident_id") {
               event.message_key = jsonObject[key];
            }*/

            /* Alternate to resource_name below, not sure which one to use
            if(key == "resource_id") {
               event.node = jsonObject[key];
            }*/

            if (key == "resource_name") { // OR resource_id depending on need
                event.node = jsonObject[key];
            }

            // Map Google state of "open" to SN state of "New", otherwise assume it's "Closing"
            if (key == "state") {
                if (jsonObject[key] == "open") {
                    event.resolution_state = "New";
                } else {
                    event.resolution_state = "Closing";
                }
            }

            // Map epoch time to SN date time
            if (key == "started_at") { // 1385085727
                event.time_of_event = convertEpochToSNTime(jsonObject[key]);
            }

            /* Not sure this is used in SN
            if (key == "ended_at") { // 1385085738
                if (jsonObject[key] > 0) {
                    event.time_of_event = convertEpochToSNTime(jsonObject[key]);
                }
            }*/

            // Map policy_name to metric_name
            if (key == "policy_name") {
                event.metric_name = jsonObject[key];
            }

            // Map condition_name to resource and type
            if (key == "condition_name") {
                event.resource = jsonObject[key];
                event.type = jsonObject[key];
            }

            // Concatenate the url and summary to the event description text
            if (key == "summary") {
                // If description is empty, add a newline before, otherwise just add the summary or url
                if (event.description == "") {
                    event.description = jsonObject[key];
                } else {
                    event.description = jsonObject[key] + '\n' + event.description;
                }
            }
            if (key == "url") {
                // If description is empty, add a newline before, otherwise just add the summary or url
                if (event.description == "") {
                    event.description = jsonObject[key];
                } else {
                    event.description = event.description + '\n' + jsonObject[key];
                }
            }

            additionalInfo[newKey] = jsonObject[key];
        }
    }

    function convertEpochToSNTime(epochTime) {
        var gdt = new GlideDateTime();
        gdt.setNumericValue(epochTime * 1000);
        return gdt.toString();
    }

    try {
        gs.info("TransformEvents_generic received body:" + body);
        var jsonObject = JSON.parse(body);
        var event = new GlideRecord('em_event');

        //TODO: Need to define
        event.source = "Google"; 

        //TODO: Need to define. Specific instance of the source. For example, SCOM 2012 on 10.20.30.40
        event.event_class = "GoogleMonitoring"; 

        //TODO: Set the event severity. All Google events will be 1-Critical. Scale is 1-5.
        event.severity = "1"; 

        var additionalInfo = {};
        updateAdditionalInfo(event, "", jsonObject, additionalInfo);
        /*Iterates over Additional information JSON object and adds all nested objects' fields as fields of the Additional information object*/
        var notDone = true;
        while (notDone) {
            notDone = false;
            for (var key in additionalInfo) {
                if (Object.prototype.toString.call(additionalInfo[key]) == '[object Object]') {
                    notDone = true;
                    updateAdditionalInfo(event, key, additionalInfo[key], additionalInfo);
                    additionalInfo[key] = "";
                }
            }
        }
        gs.info("TransformEvents_generic generated additional information:" + JSON.stringify(additionalInfo));
        event.additional_info = JSON.stringify(additionalInfo);
        event.insert();
    } catch (er) {
        gs.error(er);
        status = 500;
        return er;
    }
    return "success";
})(request, body);
View original source

https://www.servicenow.com/community/itom-articles/google-cloud-operations-monitoring-notifications-in-event/ta-p/2324265