使用 Webhook 通过 ServiceNow 发送 Azure 服务运行状况警报Send Azure service health alerts with ServiceNow using webhooks

本文介绍如何使用 Webhook 将 Azure 服务运行状况警报与 ServiceNow 集成。This article shows you how to integrate Azure service health alerts with ServiceNow using a webhook. 设置与 ServiceNow 实例的 Webhook 集成以后,当 Azure 服务问题影响你时,你会通过现有的通知基础结构获得警报。After setting up webhook integration with your ServiceNow instance, you get alerts through your existing notification infrastructure when Azure service issues affect you. Azure 服务运行状况警报在每次触发时,会通过 ServiceNow 的脚本 REST API 调用 Webhook。Every time an Azure Service Health alert fires, it calls a webhook through ServiceNow's Scripted REST API.

在 ServiceNow 中创建脚本 REST APICreating a scripted REST API in ServiceNow

  1. 请确保已注册并登录到 ServiceNow 帐户。Make sure you have signed up for and are signed into your ServiceNow account.

  2. 在 ServiceNow 中导航到“系统 Web 服务” 部分,然后选择“脚本 REST API”。 Navigate to the System Web Services section in ServiceNow and select Scripted REST APIs.

    ServiceNow 中的“脚本 Web 服务”部分

  3. 选择“新建”, 创建新的脚本 REST 服务。Select New to create a new Scripted REST service.

    ServiceNow 中的“新建脚本 REST API”按钮

  4. 为 REST API 添加“名称”,然后将“API ID”设置为 azureservicehealthAdd a Name to your REST API and set the API ID to azureservicehealth.

  5. 选择“提交”。 Select Submit.

    ServiceNow 中的“REST API 设置”

  6. 选择已创建的 REST API,然后在“资源”选项卡下选择“新建”。 Select the REST API you created, and under the Resources tab select New.

    ServiceNow 中的“资源选项卡”

  7. 为新资源 event命名,然后将“HTTP 方法”更改为 POSTName your new resource event and change the HTTP method to POST.

  8. 在“脚本” 部分,添加以下 JavaScript 代码:In the Script section, add the following JavaScript code:

    备注

    需要在下面的脚本中更新 <secret><group><email> 值。You need to update the <secret>,<group>, and <email> value in the script below.

    • <secret> 应为随机字符串,例如 GUID<secret> should be a random string, like a GUID
    • <group> 应为要向其分配事件的 ServiceNow 组<group> should be the ServiceNow group you want to assign the incident to
    • <email> 应为要向其分配事件的特定人员(可选)<email> should be the specific person you want to assign the incident to (optional)
    (function process( /*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) {
        var apiKey = request.queryParams['apiKey'];
        var secret = '<secret>';
        if (apiKey == secret) {
            var event = request.body.data;
            var responseBody = {};
            if (event.data.context.activityLog.operationName == 'Microsoft.ServiceHealth/incident/action') {
                var inc = new GlideRecord('incident');
                var incidentExists = false;
                inc.addQuery('number', event.data.context.activityLog.properties.trackingId);
                inc.query();
                if (inc.hasNext()) {
                    incidentExists = true;
                    inc.next();
                } else {
                    inc.initialize();
                }
                var short_description = "Azure Service Health";
                if (event.data.context.activityLog.properties.incidentType == "Incident") {
                    short_description += " - Service Issue - ";
                } else if (event.data.context.activityLog.properties.incidentType == "Maintenance") {
                    short_description += " - Planned Maintenance - ";
                } else if (event.data.context.activityLog.properties.incidentType == "Informational" || event.data.context.activityLog.properties.incidentType == "ActionRequired") {
                    short_description += " - Health Advisory - ";
                }
                short_description += event.data.context.activityLog.properties.title;
                inc.short_description = short_description;
                inc.description = event.data.context.activityLog.properties.communication;
                inc.work_notes = "Impacted subscription: " + event.data.context.activityLog.subscriptionId;
                if (incidentExists) {
                    if (event.data.context.activityLog.properties.stage == 'Active') {
                        inc.state = 2;
                    } else if (event.data.context.activityLog.properties.stage == 'Resolved') {
                        inc.state = 6;
                    } else if (event.data.context.activityLog.properties.stage == 'Closed') {
                        inc.state = 7;
                    }
                    inc.update();
                    responseBody.message = "Incident updated.";
                } else {
                    inc.number = event.data.context.activityLog.properties.trackingId;
                    inc.state = 1;
                    inc.impact = 2;
                    inc.urgency = 2;
                    inc.priority = 2;
                    inc.assigned_to = '<email>';
                    inc.assignment_group.setDisplayValue('<group>');
                    var subscriptionId = event.data.context.activityLog.subscriptionId;
                    var comments = "Azure portal Link: https://app.azure.com/h";
                    comments += "/" + event.data.context.activityLog.properties.trackingId;
                    comments += "/" + subscriptionId.substring(0, 3) + subscriptionId.slice(-3);
                    var impactedServices = JSON.parse(event.data.context.activityLog.properties.impactedServices);
                    var impactedServicesFormatted = "";
                    for (var i = 0; i < impactedServices.length; i++) {
                        impactedServicesFormatted += impactedServices[i].ServiceName + ": ";
                        for (var j = 0; j < impactedServices[i].ImpactedRegions.length; j++) {
                            if (j != 0) {
                                impactedServicesFormatted += ", ";
                            }
                            impactedServicesFormatted += impactedServices[i].ImpactedRegions[j].RegionName;
                        }
    
                        impactedServicesFormatted += "\n";
    
                    }
                    comments += "\n\nImpacted Services:\n" + impactedServicesFormatted;
                    inc.comments = comments;
                    inc.insert();
                    responseBody.message = "Incident created.";
                }
            } else {
                responseBody.message = "Hello from the other side!";
            }
            response.setBody(responseBody);
        } else {
            var unauthorized = new sn_ws_err.ServiceError();
            unauthorized.setStatus(401);
            unauthorized.setMessage('Invalid apiKey');
            response.setError(unauthorized);
        }
    })(request, response);
    
  9. 在安全性选项卡中,取消选择“要求身份验证”,然后选择“提交”。 In the security tab, uncheck Requires authentication and select Submit. 所设置的 <secret> 改为保护此 API。The <secret> you set protects this API instead.

    ServiceNow 中的“要求身份验证”复选框

  10. 回到“脚本 REST API”部分,此时会找到新 REST API 的“基础 API 路径”: Back at the Scripted REST APIs section, you should find the Base API Path for your new REST API:

    ServiceNow 中的“基础 API 路径”

  11. 完整的集成 URL 如下所示:Your full Integration URL looks like:

    https://<yourInstanceName>.service-now.com/<baseApiPath>?apiKey=<secret>
    

在 Azure 门户中使用 ServiceNow 创建警报Create an alert using ServiceNow in the Azure portal

对于新操作组:For a new action group:

  1. 此文中的步骤 1-8 操作,使用新操作组创建警报。Follow steps 1 through 8 in this article to create an alert with a new action group.

  2. 在“操作” 列表中定义:Define in the list of Actions:

    a.a. 操作类型: WebhookAction Type: Webhook

    b.b. 详细信息: 前面保存的 ServiceNow 集成 URL 。Details: The ServiceNow Integration URL you previously saved.

    c.c. 名称: Webhook 的名称、别名或标识符。Name: Webhook's name, alias, or identifier.

  3. 警报创建完成后,选择“保存” 。Select Save when done to create the alert.

对于现有操作组:For an existing action group:

  1. Azure 门户中,选择“监视” 。In the Azure portal, select Monitor.

  2. 在“设置” 部分中,选择“操作组” 。In the Settings section, select Action groups.

  3. 找到要编辑的操作组并选择它。Find and select the action group you want to edit.

  4. 添加到“操作” 列表:Add to the list of Actions:

    a.a. 操作类型: WebhookAction Type: Webhook

    b.b. 详细信息: 前面保存的 ServiceNow 集成 URL 。Details: The ServiceNow Integration URL you previously saved.

    c.c. 名称: Webhook 的名称、别名或标识符。Name: Webhook's name, alias, or identifier.

  5. 操作组更新完成后,选择“保存” 。Select Save when done to update the action group.

通过 HTTP POST 请求测试 Webhook 集成Testing your webhook integration via an HTTP POST request

  1. 创建要发送的服务运行状况有效负载。Create the service health payload you want to send. 可以在 Azure 活动日志警报的 Webhook 中找到示例服务运行状况 Webhook 有效负载。You can find an example service health webhook payload at Webhooks for Azure activity log alerts.

  2. 按如下所示创建 HTTP POST 请求:Create an HTTP POST request as follows:

    POST        https://<yourInstanceName>.service-now.com/<baseApiPath>?apiKey=<secret>
    
    HEADERS     Content-Type: application/json
    
    BODY        <service health payload>
    
  3. 此时会收到 200 OK 响应,其中包含消息“事件已创建”。You should receive a 200 OK response with the message "Incident created."

  4. 转到 ServiceNow,确认集成已设置成功。Go to ServiceNow to confirm that your integration was set up successfully.

后续步骤Next steps