Manage Alarms with ServiceNow
This topic explains how to file automatic ServiceNow tickets whenever alarms fire.
In this scenario, whenever CPU usage exceeds the threshold specified by your alarm, a ServiceNow ticket is created for your on-call engineer.
Do not enter confidential information when assigning descriptions, tags, or friendly names to your cloud resources through the Oracle Cloud Infrastructure Console, API, or CLI.
This scenario involves writing a function to file ServiceNow tickets (and creating a secret to store your ServiceNow credentials), adding that function and optional email as subscriptions to a topic, and creating an alarm that sends messages to that topic when the alarm threshold is exceeded. The message fans out to the topic's subscriptions, which includes a group email address in addition to the function. The function is invoked on receipt of the message.
Everything but the function can be set up in the Console. Alternatively, you can use the Oracle Cloud Infrastructure CLI or API, which lets you execute the individual operations yourself.
The following diagram illustrates the general process flow:
Store Your ServiceNow Credentials in a Secret
Create a secret that you'll reference later when you create the function.
Create a secret by using the console (you can also create a secret by using the command line interface (CLI) or the application programming interface (API)).
Create the Function
Start with the sample code below to create a function to file ServiceNow tickets and then authorize the function to access your ServiceNow credentials in the secret created using the Oracle Cloud Infrastructure Vault service.
The code sample includes variables SNOW_URL, SNOW_USER_ID_SEC, and SNOW_USER_PWD_SEC that are used in the hypothetical function. You might choose to read these values directly from the function or pass the values as custom configuration parameters instead.
#####################################################
# THIS SAMPLE CODE IS FOR DEMO PURPOSES ONLY
#*************************************************
# ******** DO NOT USE IN PRODUCTION *************
# ************************************************
#####################################################
import io
import sys
import oci
import json
import base64
import requests
from fdk import response
SNOW_URL = '<Provide Service Now URL here>'
SNOW_USER_ID_SEC = '<Provide the OCID of OCI Secret for Service Now User ID>'
SNOW_USER_PWD_SEC = '<Provide the OCID of OCI Secret for Service Now User Password>'
OCI_TO_SNOW_SEV_MAP =
{ 'CRITICAL' : '1', 'WARNING' : '2', 'ERROR' : '3', 'INFO' : '4' }
def handler(ctx, data: io.BytesIO = None):
try:
funDataStr = data.read().decode('utf-8')
funDataJSON = json.loads(funDataStr)
alarmData = {}
alarmData['type'] = funDataJSON['type']
alarmData['metaDataList'] = funDataJSON['alarmMetaData']
alarmData['title'] = funDataJSON['title']
alarmData['body'] = funDataJSON['body']
alarmData['sev'] = OCI_TO_SNOW_SEV_MAP[funDataJSON['severity'].upper()]
if alarmData['type'].upper() == 'OK_TO_FIRING':
snowURL = SNOW_URL
snowUsrIDSec = SNOW_USER_ID_SEC
snowUsrPwdSec = SNOW_USER_PWD_SEC
ociResPrncplSigner = oci.auth.signers.get_resource_principals_signer()
ociSecSvc = oci.secrets.SecretsClient(config={}, signer=ociResPrncplSigner)
snowUserID = readSecValueFromSecSvc(ociSecSvc, snowUsrIDSec)
snowPswd = readSecValueFromSecSvc(ociSecSvc, snowUsrPwdSec)
snowData = getSNOWData(alarmData)
sendDataToSnow(snowURL, snowUserID, snowPswd, snowData)
except Exception as e:
sys.stderr.write("Exception : " + str(e))
sys.stderr.write("Exception Class : " + str(e._class_))
return response.Response(ctx, response_data="", headers={"Content-Type": "application/json"})
def sendDataToSnow(snowURL, uid, pwd, snowData):
try:
{
snowHdrs =
"Content-Type" : "application/json",
counter = 0
for sd in snowData:
"Accept" : "application/json" }
snowResp = requests.post(snowURL, auth=(uid, pwd), headers=snowHdrs, data=json.dumps(sd))
except Exception as e:
sys.stderr.write("Exception : " + str(e))
sys.stderr.write("Exception Class : " + str(e._class_))
def getSNOWData(alarmData):
snowData = []
if alarmData['type'].upper() == 'OK_TO_FIRING':
alrmMD = alarmData['metaDataList'][0]
for d in alrmMD['dimensions']:
snowDataElem = {}
snowDataElem['node'] = d['resourceDisplayName']
snowDataElem['source'] = 'OCI'
snowDataElem['severity'] = alarmData['sev']
snowDataElem['description'] = alarmData['body']
snowDataElem['type'] = alarmData['title']
snowData.append(snowDataElem)
return snowData
def readSecValueFromSecSvc(ociSecSvc, secID):
secResp = ociSecSvc.get_secret_bundle(secID)
secContent = secResp.data.secret_bundle_content.content
secret_content = base64.b64decode(secContent).decode('utf-8')
return secret_content
Use a dynamic group to grant your function the ability to read secrets. Your function must have this authorization to access your ServiceNow credentials, which are stored in the secrets you created earlier.
Create the Topic
Create the topic you'll use for the subscriptions and alarm.
A topic is a communication channel for sending messages to subscriptions. Each topic name is unique across the tenancy. You can create the topic by using the console, the command line interface (CLI) or the application programming interface (API).
You must deploy the function before you can use it with a topic.
Create the Subscriptions
Create the subscription for the topic.
A subscription is an endpoint for a topic. Published messages are sent to each subscription for a topic.
You must deploy the function before you can use it with a subscription and you must have FN_INVOCATION
permission for the function to be able to add the function as a subscription to a topic.
- To create the function subscription by using the console:
- To create an optional email subscription by using the console:
- To create a subscription by using the CLI:
- To create a subscription by using the API: