本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
連接 ServiceNow
本教學課程會逐步引導您將 ServiceNow 執行個體連線至 AWS DevOps 代理程式,讓它在建立票證時自動啟動事件回應調查,並將其金鑰調查結果發佈至原始票證。它還包含如何設定 ServiceNow 執行個體僅將特定票證傳送至 DevOps 代理程式空間,以及如何協調多個 DevOps 代理程式空間之間的票證路由的範例。
初始設定
第一步是在 ServiceNow 中建立 OAuth 應用程式用戶端, AWS DevOps 可用來存取您的 ServiceNow 執行個體。
建立 ServiceNow OAuth 應用程式用戶端
啟用執行個體的用戶端登入資料系統屬性
sys_properties.list在篩選條件搜尋方塊中搜尋,然後按 Enter 鍵 (它不會顯示 選項,但按 Enter 鍵有效)選擇新增
將名稱新增為 ,
glide.oauth.inbound.client.credential.grant_type.enabled並將值新增為 true,類型為 true | false
從篩選條件搜尋方塊中導覽至系統 OAuth > 應用程式登錄檔
選擇「新」>「新傳入整合體驗」>「新整合」>「OAuth - 用戶端憑證授予」
選擇名稱並將 OAuth 應用程式使用者設定為「問題管理員」,然後按一下「儲存」
將您的 ServiceNow OAuth 用戶端連線至 AWS DevOps 代理程式
您可以從兩個位置開始此程序。首先,導覽至能力提供者頁面並在通訊下尋找 ServiceNow,然後按一下註冊。或者,您可以選擇您可能已建立的任何 DevOps 代理程式空間,並導覽至功能 → 通訊 → 新增 → ServiceNow,然後按一下註冊。
接著,授權 DevOps Agent 使用您剛建立的 OAuth 應用程式用戶端存取您的 ServiceNow 執行個體。
遵循後續步驟,並儲存 Webhook 的產生資訊
重要
您不會再看到此資訊
設定您的 ServiceNow 業務規則
建立連線後,您需要在 ServiceNow 中設定商業規則,將票證傳送至 DevOps Agent Space(s)。
導覽至活動訂閱 → 管理 → 業務規則,然後按一下新增。
將「資料表」欄位設定為「事件 【事件】」,勾選「進階」方塊,並將規則設定為在插入、更新和刪除之後執行。
導覽至「進階」索引標籤,並新增下列 Webhook 指令碼,在指示的位置插入您的 Webhook 秘密和 URL,然後按一下提交。
(function executeRule(current, previous /*null when async*/ ) { var WEBHOOK_CONFIG = { webhookSecret: GlideStringUtil.base64Encode('<<< INSERT WEBHOOK SECRET HERE >>>'), webhookUrl: '<<< INSERT WEBHOOK URL HERE >>>' }; function generateHMACSignature(payloadString, secret) { try { var mac = new GlideCertificateEncryption(); var signature = mac.generateMac(secret, "HmacSHA256", payloadString); return signature; } catch (e) { gs.error('HMAC generation failed: ' + e); return null; } } function callWebhook(payload, config) { try { var timestamp = new Date().toISOString(); var payloadString = JSON.stringify(payload); var payloadWithTimestamp =`${timestamp}:${payloadString}`; var signature = generateHMACSignature(payloadWithTimestamp, config.webhookSecret); if (!signature) { gs.error('Failed to generate signature'); return false; } gs.info('Generated signature: ' + signature); var request = new sn_ws.RESTMessageV2(); request.setEndpoint(config.webhookUrl); request.setHttpMethod('POST'); request.setRequestHeader('Content-Type', 'application/json'); request.setRequestHeader('x-amzn-event-signature', signature); request.setRequestHeader('x-amzn-event-timestamp', timestamp); request.setRequestBody(payloadString); var response = request.execute(); var httpStatus = response.getStatusCode(); var responseBody = response.getBody(); if (httpStatus >= 200 && httpStatus < 300) { gs.info('Webhook sent successfully. Status: ' + httpStatus); return true; } else { gs.error('Webhook failed. Status: ' + httpStatus + ', Response: ' + responseBody); return false; } } catch (ex) { gs.error('Error sending webhook: ' + ex.getMessage()); return false; } } function createReference(field) { if (!field || field.nil()) { return null; } return { link: field.getLink(true), value: field.toString() }; } function getStringValue(field) { if (!field || field.nil()) { return null; } return field.toString(); } function getIntValue(field) { if (!field || field.nil()) { return null; } var val = parseInt(field.toString()); return isNaN(val) ? null : val; } var eventType = (current.operation() == 'insert') ? "create" : "update"; var incidentEvent = { eventType: eventType.toString(), sysId: current.sys_id.toString(), priority: getStringValue(current.priority), impact: getStringValue(current.impact), active: getStringValue(current.active), urgency: getStringValue(current.urgency), description: getStringValue(current.description), shortDescription: getStringValue(current.short_description), parent: getStringValue(current.parent), incidentState: getStringValue(current.incident_state), severity: getStringValue(current.severity), problem: createReference(current.problem), additionalContext: {} }; incidentEvent.additionalContext = { number: current.number.toString(), opened_at: getStringValue(current.opened_at), opened_by: current.opened_by.nil() ? null : current.opened_by.getDisplayValue(), assigned_to: current.assigned_to.nil() ? null : current.assigned_to.getDisplayValue(), category: getStringValue(current.category), subcategory: getStringValue(current.subcategory), knowledge: getStringValue(current.knowledge), made_sla: getStringValue(current.made_sla), major_incident: getStringValue(current.major_incident) }; for (var key in incidentEvent.additionalContext) { if (incidentEvent.additionalContext[key] === null) { delete incidentEvent.additionalContext[key]; } } gs.info(JSON.stringify(incidentEvent, null, 2)); // Pretty print for logging only if (WEBHOOK_CONFIG.webhookUrl && WEBHOOK_CONFIG.webhookSecret) { callWebhook(incidentEvent, WEBHOOK_CONFIG); } else { gs.info('Webhook not configured.'); } })(current, previous);
如果您選擇從功能提供者頁面註冊 ServiceNow 連線,您現在需要導覽至要調查 ServiceNow 事件票證的 DevOps 代理程式空間,選取功能 → 通訊,然後在功能提供者頁面註冊您註冊的 ServiceNow 執行個體。現在,應該設定所有內容,而且呼叫者設定為「問題管理員」的所有事件 (模擬您給予 AWS DevOps OAuth 用戶端的許可) 都會在設定的 DevOps 代理程式空間中觸發事件回應調查。您可以在 ServiceNow 中建立新的事件,並將事件的來電者欄位設定為「問題管理員」,以測試這一點。
ServiceNow 票證更新
在所有觸發的事件回應調查期間,DevOps 代理程式會在原始票證中提供其關鍵調查結果、根本原因分析和緩解計劃的更新。客服人員調查結果會張貼到事件的註解,我們目前只會張貼類型為 finding、cause、、 investigation_summary mitigation_summary 和調查狀態更新的客服人員記錄 (例如 AWS DevOps Agent started/finished its investigation)。
票證路由和協同運作範例
案例:篩選哪些事件會傳送到 DevOps 代理程式空間
這是簡單的案例,但在 ServiceNow 中需要一些組態,才能在 ServiceNow 中建立欄位來追蹤事件來源。基於此範例的目的,請使用 SNOW 表單建置器建立新的來源 (u_source) 欄位。這將允許追蹤事件來源,並使用它將請求從特定來源路由到 DevOps 代理程式空間。路由的完成方式是建立 Service Now Business Rule,並在何時執行索引標籤中設定「何時」觸發條件和「篩選條件」。在此範例中,篩選條件的設定如下:
案例:跨多個 DevOps 代理程式空間路由事件
此範例示範如何在緊急程度為 1、類別為 Software 或服務為 時觸發 DevOps Agent Space B 中的調查AWS,以及在服務為 AWS且來源為 時觸發 DevOps Agent Space A 中的調查Dynatrace。
此案例可以透過兩種方式完成。Webhook 指令碼本身可以更新為包含此商業邏輯。在此案例中,我們將示範如何使用 ServiceNow 業務規則來完成它,以實現透明度並簡化偵錯。路由是透過建立兩個 Service Now Business 規則來完成。
在 ServiceNow for DevOps Agent Space A 中建立業務規則,並使用 條件建置器建立條件,只根據我們指定的條件傳送事件。
接著,在 ServiceNow for AgentSpace B 中建立另一個業務規則,只有在服務為 AWS 且來源為 Dynatrace 時,才會觸發業務規則。
現在,當您建立符合指定條件的新事件時,它會觸發對 DevOps Agent Space A 或 DevOps Agent Space B 的調查,為您提供對事件路由的精細控制。