Setting Jira Priority and Labels with OpsGenie Edge Connector
The default OpsGenie integration with Jira Service Management has a puzzling omission when it comes to their OpsGenie Edge Connector integration - it doesn't send Priority or Tags. This means that tags won't pass through as labels, and the priority will be at the default.
My ideal is that the Jira priority maps directly to the OpsGenie priority, especially when SLAs are set against those priorities. Tags and labels power automation, reporting, and documentation in our environment - so passing them through is a must.
Now obviously Atlassian is pivoting to retire their server products and offer "cloud only" by 2024, while working to more closely integrate OpsGenie with their Jira Service Management offering, but for those still using an on-premise server and OpsGenie, this might be of help.
I haven't had cause to do a lot with Python before, but I modified the actionExecutor.py to perform a query against the OpsGenie Alerts API before creating the Jira ticket. It retrieves the priority and tags, maps OpsGenie priorities to the standard Jira priorities (eg. P1 = Highest), and adds the tags as Jira labels.
I also add a static "OpsGenie" label, because I have some Jira Automation rules that work against that label to fire off webhooks back to OpsGenie.
In our environment, "P5" priorities don't exist - so I map a P5 to Low rather than Lowest. That's relatively trivial to change in the script if you need to.
The amended script is below, or you can grab it from my Github fork.
import argparse
import json
import logging
import sys
import requests
from requests.auth import HTTPBasicAuth
parser = argparse.ArgumentParser()
parser.add_argument('-payload', '--queuePayload', help='Payload from queue', required=True)
parser.add_argument('-apiKey', '--apiKey', help='The apiKey of the integration', required=True)
parser.add_argument('-opsgenieUrl', '--opsgenieUrl', help='The url', required=True)
parser.add_argument('-logLevel', '--logLevel', help='Level of log', required=True)
parser.add_argument('-url', '--url', help='URL', required=False)
parser.add_argument('-username', '--username', help='Username', required=False)
parser.add_argument('-password', '--password', help='Password', required=False)
parser.add_argument('-key', '--key', help='Project key', required=False)
parser.add_argument('-issueTypeName', '--issueTypeName', help='Issue Type', required=False)
args = vars(parser.parse_args())
logging.basicConfig(stream=sys.stdout, level=args['logLevel'])
def parse_field(key, mandatory):
variable = queue_message.get(key)
if not variable:
variable = args.get(key)
if mandatory and not variable:
logging.error(LOG_PREFIX + " Skipping action, Mandatory conf item '" + key +
"' is missing. Check your configuration file.")
raise ValueError(LOG_PREFIX + " Skipping action, Mandatory conf item '" + key +
"' is missing. Check your configuration file.")
return variable
def parse_timeout():
parsed_timeout = args.get('http.timeout')
if not parsed_timeout:
return 30000
return int(parsed_timeout)
def get_transition_id(request_headers, jira_url, transition_name, token):
transition_id = str()
response = requests.get(jira_url, None, headers=request_headers, auth=token, timeout=timeout)
body = response.json()
if body != {} and response.status_code < 299:
transition_list = body["transitions"]
for transition in transition_list:
to = transition['to']
if transition_name == to['name']:
transition_id = transition['id']
logging.info(LOG_PREFIX + " Successfully executed at Jira Service Desk")
logging.debug(
LOG_PREFIX + " Jira Service Desk response: " + str(response.status_code) + " " + str(response.content))
else:
logging.error(
LOG_PREFIX + " Could not execute at Jira Service Desk; response: " + str(
response.content) + " status code: " + str(response.status_code))
if transition_id:
return transition_id
else:
logging.debug(LOG_PREFIX + " Transition id is empty")
def get_alert(opsgenieUrl, api_Key, alert_id):
headers = {
"Content-Type": "application/json",
"Accept-Language": "application/json",
"Authorization": "GenieKey " + args.get('apiKey')
}
alert_api_url = opsgenieUrl + "/v2/alerts/" + alert_id + '?identifierType=id'
alert_response = requests.get(alert_api_url, headers=headers, timeout=timeout)
if alert_response.status_code < 299:
logging.info(LOG_PREFIX + " Successfully requested alert from Opsgenie")
logging.debug(
LOG_PREFIX + "OpsGenie response: " + str(alert_response.content) + " " + str(
alert_response.status_code))
return alert_response.json()
else:
logging.warning(
LOG_PREFIX + " Could not execute at Opsgenie; response: " + str(
alert_response.content) + " status code: " + str(alert_response.status_code))
def get_tags(alert):
return alert['data']['tags']
def get_priority(alert):
priorities = {"P1":"Highest","P2":"High","P3":"Medium","P4":"Low","P5":"Low"}
priorityMap = "{" + alert["data"]["priority"] + "}"
logging.debug(priorityMap + ' result: ' + priorityMap.format_map(priorities))
return priorityMap.format_map(priorities)
def main():
global LOG_PREFIX
global queue_message
global timeout
queue_message_string = args['queuePayload']
queue_message = json.loads(queue_message_string)
logging.debug(str(queue_message))
alert_id = queue_message["alert"]["alertId"]
mapped_action = queue_message["mappedActionV2"]["name"]
LOG_PREFIX = "[" + mapped_action + "]"
logging.info("Will execute " + mapped_action + " for alertId " + alert_id)
timeout = parse_timeout()
url = parse_field('url', True)
username = parse_field('username', True)
password = parse_field('password', True)
project_key = parse_field('key', False)
issue_type_name = parse_field('issueTypeName', False)
issue_key = queue_message.get("IssueKey")
logging.debug("Url: " + str(url))
logging.debug("Username: " + str(username))
logging.debug("Project Key: " + str(project_key))
logging.debug("Issue Type: " + str(issue_type_name))
logging.debug("Issue Key: " + str(issue_key))
content_params = dict()
token = HTTPBasicAuth(username, password)
headers = {
"Content-Type": "application/json",
"Accept-Language": "application/json"
}
result_url = url + "/rest/api/2/issue"
if mapped_action == "addComment":
content_params = {
"body": queue_message.get('body')
}
result_url += "/" + str(issue_key) + "/comment"
elif mapped_action == "createIssue":
toLabel = queue_message.get("alias")
alert = get_alert(args.get('opsgenieUrl'), args.get('apiKey'), alert_id)
priority = get_priority(alert)
labels = get_tags(alert)
labels.append(toLabel)
labels.append("OpsGenie")
content_params = {
"fields": {
"project": {
"key": project_key
},
"issuetype": {
"name": issue_type_name
},
"summary": queue_message.get("summary"),
"description": queue_message.get("description"),
"priority": { "name": priority },
"labels": labels
}
}
elif mapped_action == "resolveIssue":
result_url += "/" + str(issue_key) + "/transitions"
content_params = {
"transition": {
"id": get_transition_id(headers, result_url, "Resolved", token)
},
"fields": {
"resolution": {
"name": "Done"
}
}
}
logging.debug(str(content_params))
response = requests.post(result_url, data=json.dumps(content_params), headers=headers, auth=token, timeout=timeout)
if response.status_code < 299:
logging.info("Successfully executed at Jira Service Desk")
if mapped_action == "createIssue":
if response.json():
issue_key_from_response = response.json()['key']
if issue_key_from_response:
alert_api_url = args.get('opsgenieUrl') + "/v2/alerts/" + alert_id + "/details"
content = {
"details":
{
"issueKey": issue_key_from_response
}
}
headers = {
"Content-Type": "application/json",
"Accept-Language": "application/json",
"Authorization": "GenieKey " + args.get('apiKey')
}
alert_response = requests.post(alert_api_url,
data=json.dumps(content), headers=headers, timeout=timeout)
if alert_response.status_code < 299:
logging.info(LOG_PREFIX + " Successfully sent to Opsgenie")
logging.debug(
LOG_PREFIX + " Jira Service Desk response: " + str(alert_response.content) + " " + str(
alert_response.status_code))
else:
logging.warning(
LOG_PREFIX + " Could not execute at Opsgenie; response: " + str(
alert_response.content) + " status code: " + str(alert_response.status_code))
else:
logging.warning(
LOG_PREFIX + " Jira Service Desk response is empty")
else:
logging.warning(
LOG_PREFIX + " Could not execute at Jira Service Desk; response: " + str(
response.content) + " status code: " + str(response.status_code))
if __name__ == '__main__':
main()
Comments