Opsgenie
Our Opsgenie integration allows you to import alert
, service
and incident
from your Opsgenie account into Port, according to your mapping and definitions.
Common use cases
- Map
alert
,service
andincident
in your Opsgenie account. - Watch for object changes (create/update/delete) in real-time, and automatically apply the changes to your entities in Port.
Prerequisites
To install the integration, you need a Kubernetes cluster that the integration's container chart will be deployed to.
Please make sure that you have kubectl
and helm
installed on your machine, and that your kubectl
CLI is connected to the Kubernetes cluster where you plan to install the integration.
If you are having trouble installing this integration, please refer to these troubleshooting steps.
Installation
Choose one of the following installation methods:
- Real Time & Always On
- Scheduled
Using this installation option means that the integration will be able to update Port in real time using webhooks.
This table summarizes the available parameters for the installation. Set them as you wish in the script below, then copy it and run it in your terminal:
Parameter | Description | Required |
---|---|---|
port.clientId | Your port client id | ✅ |
port.clientSecret | Your port client secret | ✅ |
port.baseUrl | Your Port API URL - https://api.getport.io for EU, https://api.us.getport.io for US | ✅ |
integration.identifier | Change the identifier to describe your integration | ✅ |
integration.type | The integration type | ✅ |
integration.eventListener.type | The event listener type | ✅ |
integration.secrets.apiToken | The Opsgenie API token | ✅ |
integration.config.apiUrl | The Opsgenie API URL. If not specified, the default will be https://api.opsgenie.com | ✅ |
scheduledResyncInterval | The number of minutes between each resync | ❌ |
initializePortResources | Default true, When set to true the integration will create default blueprints and the port App config Mapping | ❌ |
- Helm
- ArgoCD
To install the integration using Helm, run the following command:
helm repo add --force-update port-labs https://port-labs.github.io/helm-charts
helm upgrade --install my-opsgenie-integration port-labs/port-ocean \
--set port.clientId="CLIENT_ID" \
--set port.clientSecret="CLIENT_SECRET" \
--set port.baseUrl="https://api.getport.io" \
--set initializePortResources=true \
--set integration.identifier="my-opsgenie-integration" \
--set integration.type="opsgenie" \
--set integration.eventListener.type="POLLING" \
--set integration.secrets.apiToken="API_TOKEN" \
--set integration.config.apiUrl="https://api.opsgenie.com"
The baseUrl
, port_region
, port.baseUrl
, portBaseUrl
, port_base_url
and OCEAN__PORT__BASE_URL
parameters are used to select which instance or Port API will be used.
Port exposes two API instances, one for the EU region of Port, and one for the US region of Port.
- If you use the EU region of Port, available at https://app.getport.io, your Port API URL is
https://api.getport.io
- If you use the US region of Port, available at https://app.us.getport.io, your Port API URL is
https://api.us.getport.io
To install the integration using ArgoCD, follow these steps:
- Create a
values.yaml
file inargocd/my-ocean-opsgenie-integration
in your git repository with the content:
Remember to replace the placeholders for OPSGENIE_API_URL
and OPSGENIE_API_TOKEN
.
initializePortResources: true
scheduledResyncInterval: 120
integration:
identifier: my-ocean-opsgenie-integration
type: opsgenie
eventListener:
type: POLLING
config:
apiUrl: OPSGENIE_API_URL
secrets:
apiToken: OPSGENIE_API_TOKEN
- Install the
my-ocean-opsgenie-integration
ArgoCD Application by creating the followingmy-ocean-opsgenie-integration.yaml
manifest:
Remember to replace the placeholders for YOUR_PORT_CLIENT_ID
YOUR_PORT_CLIENT_SECRET
and YOUR_GIT_REPO_URL
.
Multiple sources ArgoCD documentation can be found here.
ArgoCD Application
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-ocean-opsgenie-integration
namespace: argocd
spec:
destination:
namespace: my-ocean-opsgenie-integration
server: https://kubernetes.default.svc
project: default
sources:
- repoURL: 'https://port-labs.github.io/helm-charts/'
chart: port-ocean
targetRevision: 0.1.14
helm:
valueFiles:
- $values/argocd/my-ocean-opsgenie-integration/values.yaml
parameters:
- name: port.clientId
value: YOUR_PORT_CLIENT_ID
- name: port.clientSecret
value: YOUR_PORT_CLIENT_SECRET
- name: port.baseUrl
value: https://api.getport.io
- repoURL: YOUR_GIT_REPO_URL
targetRevision: main
ref: values
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
The baseUrl
, port_region
, port.baseUrl
, portBaseUrl
, port_base_url
and OCEAN__PORT__BASE_URL
parameters are used to select which instance or Port API will be used.
Port exposes two API instances, one for the EU region of Port, and one for the US region of Port.
- If you use the EU region of Port, available at https://app.getport.io, your Port API URL is
https://api.getport.io
- If you use the US region of Port, available at https://app.us.getport.io, your Port API URL is
https://api.us.getport.io
- Apply your application manifest with
kubectl
:
kubectl apply -f my-ocean-opsgenie-integration.yaml
- GitHub
- Jenkins
- Azure Devops
- GitLab
This workflow will run the Opsgenie integration once and then exit, this is useful for scheduled ingestion of data.
If you want the integration to update Port in real time using webhooks you should use the Real Time & Always On installation option
Make sure to configure the following Github Secrets:
Parameter | Description | Required |
---|---|---|
OCEAN__INTEGRATION__CONFIG__API_TOKEN | The Opsgenie API token | ✅ |
OCEAN__INTEGRATION__CONFIG__API_URL | The Opsgenie API URL | ✅ |
OCEAN__INITIALIZE_PORT_RESOURCES | Default true, When set to false the integration will not create default blueprints and the port App config Mapping | ❌ |
OCEAN__INTEGRATION__IDENTIFIER | Change the identifier to describe your integration, if not set will use the default one | ❌ |
OCEAN__PORT__CLIENT_ID | Your port client id | ✅ |
OCEAN__PORT__CLIENT_SECRET | Your port client secret | ✅ |
OCEAN__PORT__BASE_URL | Your Port API URL - https://api.getport.io for EU, https://api.us.getport.io for US | ✅ |
Here is an example for opsgenie-integration.yml
workflow file:
name: Opsgenie Exporter Workflow
# This workflow responsible for running Opsgenie exporter.
on:
workflow_dispatch:
jobs:
run-integration:
runs-on: ubuntu-latest
steps:
- uses: port-labs/ocean-sail@v1
with:
type: 'opsgenie'
port_client_id: ${{ secrets.OCEAN__PORT__CLIENT_ID }}
port_client_secret: ${{ secrets.OCEAN__PORT__CLIENT_SECRET }}
port_base_url: https://api.getport.io
config: |
api_token: ${{ secrets.OCEAN__INTEGRATION__CONFIG__API_TOKEN }}
api_url: ${{ secrets.OCEAN__INTEGRATION__CONFIG__API_URL }}
This pipeline will run the Opsgenie integration once and then exit, this is useful for scheduled ingestion of data.
Your Jenkins agent should be able to run docker commands.
If you want the integration to update Port in real time using webhooks you should use the Real Time & Always On installation option.
Make sure to configure the following Jenkins Credentials
of Secret Text
type:
Parameter | Description | Required |
---|---|---|
OCEAN__INTEGRATION__CONFIG__API_TOKEN | The Opsgenie API token | ✅ |
OCEAN__INTEGRATION__CONFIG__API_URL | The Opsgenie API URL | ✅ |
OCEAN__INITIALIZE_PORT_RESOURCES | Default true, When set to false the integration will not create default blueprints and the port App config Mapping | ❌ |
OCEAN__INTEGRATION__IDENTIFIER | Change the identifier to describe your integration, if not set will use the default one | ❌ |
OCEAN__PORT__CLIENT_ID | Your port client id | ✅ |
OCEAN__PORT__CLIENT_SECRET | Your port client secret | ✅ |
OCEAN__PORT__BASE_URL | Your Port API URL - https://api.getport.io for EU, https://api.us.getport.io for US | ✅ |
Here is an example for Jenkinsfile
groovy pipeline file:
pipeline {
agent any
stages {
stage('Run Opsgenie Integration') {
steps {
script {
withCredentials([
string(credentialsId: 'OCEAN__INTEGRATION__CONFIG__API_TOKEN', variable: 'OCEAN__INTEGRATION__CONFIG__API_TOKEN'),
string(credentialsId: 'OCEAN__INTEGRATION__CONFIG__API_URL', variable: 'OCEAN__INTEGRATION__CONFIG__API_URL'),
string(credentialsId: 'OCEAN__PORT__CLIENT_ID', variable: 'OCEAN__PORT__CLIENT_ID'),
string(credentialsId: 'OCEAN__PORT__CLIENT_SECRET', variable: 'OCEAN__PORT__CLIENT_SECRET'),
]) {
sh('''
#Set Docker image and run the container
integration_type="opsgenie"
version="latest"
image_name="ghcr.io/port-labs/port-ocean-${integration_type}:${version}"
docker run -i --rm --platform=linux/amd64 \
-e OCEAN__EVENT_LISTENER='{"type":"ONCE"}' \
-e OCEAN__INITIALIZE_PORT_RESOURCES=true \
-e OCEAN__INTEGRATION__CONFIG__API_TOKEN=$OCEAN__INTEGRATION__CONFIG__API_TOKEN \
-e OCEAN__INTEGRATION__CONFIG__API_URL=$OCEAN__INTEGRATION__CONFIG__API_URL \
-e OCEAN__PORT__CLIENT_ID=$OCEAN__PORT__CLIENT_ID \
-e OCEAN__PORT__CLIENT_SECRET=$OCEAN__PORT__CLIENT_SECRET \
-e OCEAN__PORT__BASE_URL='https://api.getport.io' \
$image_name
exit $?
''')
}
}
}
}
}
}
This pipeline will run the Opsgenie integration once and then exit, this is useful for scheduled ingestion of data.
Your Azure Devops agent should be able to run docker commands. Learn more about agents here.
If you want the integration to update Port in real time using webhooks you should use the Real Time & Always On installation option.
Variable groups store values and secrets you'll use in your pipelines across your project. Learn more
Setting Up Your Credentials
- Create a Variable Group: Name it port-ocean-credentials. Store the required variables from the table.
- Authorize Your Pipeline:
- Go to "Library" -> "Variable groups."
- Find port-ocean-credentials and click on it.
- Select "Pipeline Permissions" and add your pipeline to the authorized list.
Parameter | Description | Required |
---|---|---|
OCEAN__INTEGRATION__CONFIG__API_TOKEN | The Opsgenie API token | ✅ |
OCEAN__INTEGRATION__CONFIG__API_URL | The Opsgenie API URL | ✅ |
OCEAN__INITIALIZE_PORT_RESOURCES | Default true, When set to false the integration will not create default blueprints and the port App config Mapping | ❌ |
OCEAN__INTEGRATION__IDENTIFIER | Change the identifier to describe your integration, if not set will use the default one | ❌ |
OCEAN__PORT__CLIENT_ID | Your port client id | ✅ |
OCEAN__PORT__CLIENT_SECRET | Your port client secret | ✅ |
OCEAN__PORT__BASE_URL | Your Port API URL - https://api.getport.io for EU, https://api.us.getport.io for US | ✅ |
Here is an example for opsgenie-integration.yml
pipeline file:
trigger:
- main
pool:
vmImage: "ubuntu-latest"
variables:
- group: port-ocean-credentials
steps:
- script: |
# Set Docker image and run the container
integration_type="opsgenie"
version="latest"
image_name="ghcr.io/port-labs/port-ocean-$integration_type:$version"
docker run -i --rm --platform=linux/amd64 \
-e OCEAN__EVENT_LISTENER='{"type":"ONCE"}' \
-e OCEAN__INITIALIZE_PORT_RESOURCES=true \
-e OCEAN__INTEGRATION__CONFIG__API_TOKEN=$(OCEAN__INTEGRATION__CONFIG__API_TOKEN) \
-e OCEAN__INTEGRATION__CONFIG__API_URL=$(OCEAN__INTEGRATION__CONFIG__API_URL) \
-e OCEAN__PORT__CLIENT_ID=$(OCEAN__PORT__CLIENT_ID) \
-e OCEAN__PORT__CLIENT_SECRET=$(OCEAN__PORT__CLIENT_SECRET) \
-e OCEAN__PORT__BASE_URL='https://api.getport.io' \
$image_name
exit $?
displayName: 'Ingest Data into Port'
This workflow will run the Opsgenie integration once and then exit, this is useful for scheduled ingestion of data.
If you want the integration to update Port in real time using webhooks you should use the Real Time & Always On installation option.
Make sure to configure the following GitLab variables:
Parameter | Description | Required |
---|---|---|
OCEAN__INTEGRATION__CONFIG__API_TOKEN | The Opsgenie API token | ✅ |
OCEAN__INTEGRATION__CONFIG__API_URL | The Opsgenie API URL | ✅ |
OCEAN__INITIALIZE_PORT_RESOURCES | Default true, When set to false the integration will not create default blueprints and the port App config Mapping | ❌ |
OCEAN__INTEGRATION__IDENTIFIER | Change the identifier to describe your integration, if not set will use the default one | ❌ |
OCEAN__PORT__CLIENT_ID | Your port client id | ✅ |
OCEAN__PORT__CLIENT_SECRET | Your port client secret | ✅ |
OCEAN__PORT__BASE_URL | Your Port API URL - https://api.getport.io for EU, https://api.us.getport.io for US | ✅ |
Here is an example for .gitlab-ci.yml
pipeline file:
default:
image: docker:24.0.5
services:
- docker:24.0.5-dind
before_script:
- docker info
variables:
INTEGRATION_TYPE: opsgenie
VERSION: latest
stages:
- ingest
ingest_data:
stage: ingest
variables:
IMAGE_NAME: ghcr.io/port-labs/port-ocean-$INTEGRATION_TYPE:$VERSION
script:
- |
docker run -i --rm --platform=linux/amd64 \
-e OCEAN__EVENT_LISTENER='{"type":"ONCE"}' \
-e OCEAN__INITIALIZE_PORT_RESOURCES=true \
-e OCEAN__INTEGRATION__CONFIG__API_TOKEN=$OCEAN__INTEGRATION__CONFIG__API_TOKEN \
-e OCEAN__INTEGRATION__CONFIG__API_URL=$OCEAN__INTEGRATION__CONFIG__API_URL \
-e OCEAN__PORT__CLIENT_ID=$OCEAN__PORT__CLIENT_ID \
-e OCEAN__PORT__CLIENT_SECRET=$OCEAN__PORT__CLIENT_SECRET \
-e OCEAN__PORT__BASE_URL='https://api.getport.io' \
$IMAGE_NAME
rules: # Run only when changes are made to the main branch
- if: '$CI_COMMIT_BRANCH == "main"'
The baseUrl
, port_region
, port.baseUrl
, portBaseUrl
, port_base_url
and OCEAN__PORT__BASE_URL
parameters are used to select which instance or Port API will be used.
Port exposes two API instances, one for the EU region of Port, and one for the US region of Port.
- If you use the EU region of Port, available at https://app.getport.io, your Port API URL is
https://api.getport.io
- If you use the US region of Port, available at https://app.us.getport.io, your Port API URL is
https://api.us.getport.io
For advanced configuration such as proxies or self-signed certificates, click here.
Ingesting Opsgenie objects
The Opsgenie integration uses a YAML configuration to describe the process of loading data into the developer portal. See examples below.
The integration makes use of the JQ JSON processor to select, modify, concatenate, transform and perform other operations on existing fields and values from Opsgenie's API events.
Configuration structure
The integration configuration determines which resources will be queried from Opsgenie, and which entities and properties will be created in Port.
-
The root key of the integration configuration is the
resources
key:resources:
- kind: service
selector:
... -
The
kind
key is a specifier for a Opsgenie object:resources:
- kind: service
selector:
... -
The
selector
and thequery
keys allow you to filter which objects of the specifiedkind
will be ingested into your software catalog:resources:
- kind: service
selector:
query: "true" # JQ boolean expression. If evaluated to false - this object will be skipped.
port: -
The
port
,entity
and themappings
keys are used to map the Opsgenie object fields to Port entities. To create multiple mappings of the same kind, you can add another item in theresources
array;resources:
- kind: service
selector:
query: "true"
port:
entity:
mappings: # Mappings between one Opsgenie object to a Port entity. Each value is a JQ query.
identifier: .id
title: .name
blueprint: '"opsGenieService"'
properties:
description: .description
- kind: service # In this instance service is mapped again with a different filter
selector:
query: '.name == "MyServiceName"'
port:
entity:
mappings: ...Blueprint keyNote the value of the
blueprint
key - if you want to use a hardcoded string, you need to encapsulate it in 2 sets of quotes, for example use a pair of single-quotes ('
) and then another pair of double-quotes ("
)
Configuring real-time updates
Currently, the OpsGenie API lacks support for programmatic webhook creation. To set up a webhook configuration in OpsGenie for sending alert notifications to the Ocean integration, follow these steps:
Prerequisite
Prepare a webhook URL
using this format: {app_host}/integration/webhook
. The app_host
parameter should match the ingress or external load balancer where the integration will be deployed. For example, if your ingress or load balancer exposes the OpsGenie Ocean integration at https://myservice.domain.com
, your webhook URL
should be https://myservice.domain.com/integration/webhook
.
Create a webhook in OpsGenie
- Go to OpsGenie;
- Select Settings;
- Click on Integrations under the Integrations section of the sidebar;
- Click on Add integration;
- In the search box, type Webhook and select the webhook option;
- Input the following details:
Name
- use a meaningful name such as Port Ocean Webhook;- Be sure to keep the "Enabled" checkbox checked;
- Check the "Add Alert Description to Payload" checkbox;
- Check the "Add Alert Details to Payload" checkbox;
- Add the following action triggers to the webhook by clicking on Add new action:
- If alert is snoozed in Opsgenie, post to url in Webhook;
- If alert's description is updated in Opsgenie, post to url in Webhook;
- If alert's message is updated in Opsgenie, post to url in Webhook;
- If alert's priority is updated in Opsgenie, post to url in Webhook;
- If a responder is added to the alert in Opsgenie, post to url in Webhook;
- if a user executes "Assign Ownership in Opsgenie, post to url in Webhook;
- if a tag is added to the alert in Opsgenie, post to url in Webhook;
- .if a tag is removed from the alert in Opsgenie, post to url in Webhook;
Webhook URL
- enter the value of theURL
you created above.
- Click Save integration
Ingest data into Port
To ingest Opsgenie objects using the integration configuration, you can follow the steps below:
- Go to the DevPortal Builder page.
- Select a blueprint you want to ingest using Opsgenie.
- Choose the Ingest Data option from the menu.
- Select Opsgenie under the Incident management category.
- Modify the configuration according to your needs.
- Click
Resync
.
Examples
Examples of blueprints and the relevant integration configurations:
Service
Service blueprint
{
"identifier": "opsGenieService",
"description": "This blueprint represents an OpsGenie service in our software catalog",
"title": "OpsGenie Service",
"icon": "OpsGenie",
"schema": {
"properties": {
"description": {
"type": "string",
"title": "Description",
"icon": "DefaultProperty"
},
"url": {
"title": "URL",
"type": "string",
"description": "URL to the service",
"format": "url",
"icon": "DefaultProperty"
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"title": "Tags",
"icon": "DefaultProperty"
},
"oncallTeam": {
"type": "string",
"title": "OnCall Team",
"description": "Name of the team responsible for this service",
"icon": "DefaultProperty"
},
"teamMembers": {
"icon": "TwoUsers",
"type": "array",
"items": {
"type": "string",
"format": "user"
},
"title": "Team Members",
"description": "Members of team responsible for this service"
},
"oncallUsers": {
"icon": "TwoUsers",
"type": "array",
"items": {
"type": "string",
"format": "user"
},
"title": "Oncall Users",
"description": "Who is on call for this service"
},
"numOpenIncidents": {
"title": "Number of Open Incidents",
"type": "number"
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {
"teamSize": {
"title": "Team Size",
"icon": "DefaultProperty",
"description": "Size of the team",
"calculation": ".properties.teamMembers | length",
"type": "number"
}
},
"relations": {}
}
Integration configuration
createMissingRelatedEntities: true
deleteDependentEntities: true
resources:
- kind: service
selector:
query: "true"
port:
entity:
mappings:
identifier: .name | gsub("[^a-zA-Z0-9@_.:/=-]"; "-") | tostring
title: .name
blueprint: '"opsGenieService"'
properties:
description: .description
url: .links.web
tags: .tags
oncallTeam: .__team.name
teamMembers: "[.__team.members[].user.username]"
oncallUsers: .__oncalls.onCallRecipients
numOpenIncidents: '[ .__incidents[] | select(.status == "open")] | length'
Incident
Incident blueprint
{
"identifier": "opsGenieIncident",
"description": "This blueprint represents an OpsGenie incident in our software catalog",
"title": "OpsGenie Incident",
"icon": "OpsGenie",
"schema": {
"properties": {
"description": {
"title": "Description",
"type": "string"
},
"status": {
"type": "string",
"title": "Status",
"enum": ["closed", "open", "resolved"],
"enumColors": {
"closed": "blue",
"open": "red",
"resolved": "green"
},
"description": "The status of the incident"
},
"url": {
"type": "string",
"format": "url",
"title": "URL"
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"title": "Tags"
},
"responders": {
"type": "array",
"title": "Responders",
"description": "Responders to the alert"
},
"priority": {
"type": "string",
"title": "Priority"
},
"createdAt": {
"title": "Create At",
"type": "string",
"format": "date-time"
},
"updatedAt": {
"title": "Updated At",
"type": "string",
"format": "date-time"
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"relations": {
"services": {
"title": "Impacted Services",
"target": "opsGenieService",
"many": true,
"required": false
}
}
}
Integration configuration
createMissingRelatedEntities: true
deleteDependentEntities: true
resources:
- kind: incident
selector:
query: "true"
port:
entity:
mappings:
identifier: .id
title: .message
blueprint: '"opsGenieIncident"'
properties:
status: .status
responders: .responders
priority: .priority
tags: .tags
url: .links.web
createdAt: .createdAt
updatedAt: .updatedAt
description: .description
relations:
services: '[.__impactedServices[] | .name | gsub("[^a-zA-Z0-9@_.:/=-]"; "-") | tostring]'
Alert
Alert blueprint
{
"identifier": "opsGenieAlert",
"description": "This blueprint represents an OpsGenie alert in our software catalog",
"title": "OpsGenie Alert",
"icon": "OpsGenie",
"schema": {
"properties": {
"description": {
"title": "Description",
"type": "string"
},
"status": {
"type": "string",
"title": "Status",
"enum": ["closed", "open"],
"enumColors": {
"closed": "green",
"open": "red"
},
"description": "The status of the alert"
},
"acknowledged": {
"type": "boolean",
"title": "Acknowledged"
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"title": "Tags"
},
"responders": {
"type": "array",
"title": "Responders",
"description": "Responders to the alert"
},
"integration": {
"type": "string",
"title": "Integration",
"description": "The name of the Integration"
},
"priority": {
"type": "string",
"title": "Priority"
},
"sourceName": {
"type": "string",
"title": "Source Name",
"description": "Alert source name"
},
"createdBy": {
"title": "Created By",
"type": "string",
"format": "user"
},
"createdAt": {
"title": "Create At",
"type": "string",
"format": "date-time"
},
"updatedAt": {
"title": "Updated At",
"type": "string",
"format": "date-time"
},
"count": {
"title": "Count",
"type": "number"
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"relations": {
"relatedIncident": {
"title": "Related Incident",
"target": "opsGenieIncident",
"required": false,
"many": false
}
}
}
Integration configuration
createMissingRelatedEntities: true
deleteDependentEntities: true
resources:
- kind: alert
selector:
query: "true"
port:
entity:
mappings:
identifier: .id
title: .message
blueprint: '"opsGenieAlert"'
properties:
status: .status
acknowledged: .acknowledged
responders: .responders
priority: .priority
sourceName: .source
tags: .tags
count: .count
createdBy: .owner
createdAt: .createdAt
updatedAt: .updatedAt
description: .description
integration: .integration.name
relations:
relatedIncident: .__relatedIncident.id
Let's Test It
This section includes a sample response data from Opsgenie. In addition, it includes the entity created from the resync event based on the Ocean configuration provided in the previous section.
Payload
Here is an example of the payload structure from Opsgenie:
Service response data
{
"id": "daa0d66f-ad35-4396-b30d-70f0314c697a",
"name": "Port Outbound Service",
"description": "For outbound communications and integrations",
"teamId": "63374eee-0b03-42d4-bb8c-50d1fa64827c",
"tags": ["communication", "channel"],
"links": {
"web": "https://mytestaccount.app.opsgenie.com/service/daa0d66f-ad35-4396-b30d-70f0314c697a/status",
"api": "https://api.opsgenie.com/v1/services/daa0d66f-ad35-4396-b30d-70f0314c697a"
},
"isExternal": false,
"__team": {
"id": "63374eee-0b03-42d4-bb8c-50d1fa64827c",
"name": "Data Science Team",
"description": "",
"members": [
{
"user": {
"id": "ce544b61-7b35-43ea-89ee-a8750638d3a4",
"username": "testuser@gmail.com"
},
"role": "admin"
},
{
"user": {
"id": "9ea8f86a-6648-46d6-a2fc-1a6eb5f739c8",
"username": "devtester@gmail.com"
},
"role": "user"
}
],
"links": {
"web": "https://app.opsgenie.com/teams/dashboard/63374eee-0b03-42d4-bb8c-50d1fa64827c/main",
"api": "https://api.opsgenie.com/v2/teams/63374eee-0b03-42d4-bb8c-50d1fa64827c"
}
},
"__incidents": [
{
"id": "652f14b3-019a-4d4c-8b83-e4da527a416c",
"description": "summary",
"impactedServices": ["daa0d66f-ad35-4396-b30d-70f0314c697a"],
"tinyId": "3",
"message": "OpenAI Incident",
"status": "open",
"tags": ["tags"],
"createdAt": "2023-09-26T17:06:16.824Z",
"updatedAt": "2023-09-26T17:49:10.17Z",
"priority": "P3",
"ownerTeam": "",
"responders": [
{
"type": "team",
"id": "63374eee-0b03-42d4-bb8c-50d1fa64827c"
},
{
"type": "user",
"id": "ce544b61-7b35-43ea-89ee-a8750638d3a4"
}
],
"extraProperties": {},
"links": {
"web": "https://mytestaccount.app.opsgenie.com/incident/detail/652f14b3-019a-4d4c-8b83-e4da527a416c",
"api": "https://api.opsgenie.com/v1/incidents/652f14b3-019a-4d4c-8b83-e4da527a416c"
},
"impactStartDate": "2023-09-26T17:06:16.824Z",
"impactEndDate": "2023-09-26T17:45:25.719Z",
"actions": []
},
{
"id": "4a0c5e6d-b239-4cd9-a7e8-a5f880e99473",
"description": "descirption",
"impactedServices": [
"59591948-d418-4bb9-af16-170d6b232b7d",
"daa0d66f-ad35-4396-b30d-70f0314c697a"
],
"tinyId": "2",
"message": "My Incident",
"status": "open",
"tags": ["hello"],
"createdAt": "2023-09-20T13:33:00.941Z",
"updatedAt": "2023-09-26T17:48:54.48Z",
"priority": "P3",
"ownerTeam": "",
"responders": [
{
"type": "team",
"id": "63374eee-0b03-42d4-bb8c-50d1fa64827c"
},
{
"type": "user",
"id": "ce544b61-7b35-43ea-89ee-a8750638d3a4"
},
{
"type": "user",
"id": "9ea8f86a-6648-46d6-a2fc-1a6eb5f739c8"
}
],
"extraProperties": {},
"links": {
"web": "https://mytestaccount.app.opsgenie.com/incident/detail/4a0c5e6d-b239-4cd9-a7e8-a5f880e99473",
"api": "https://api.opsgenie.com/v1/incidents/4a0c5e6d-b239-4cd9-a7e8-a5f880e99473"
},
"impactStartDate": "2023-09-20T13:33:00.941Z",
"actions": []
}
],
"__oncalls": {
"_parent": {
"id": "d55e148e-d320-4766-9dcf-4fc2ce9daef1",
"name": "Data Science Team_schedule",
"enabled": true
},
"onCallRecipients": ["testuser@gmail.com"]
}
}
Incident response data
{
"id": "4a0c5e6d-b239-4cd9-a7e8-a5f880e99473",
"description": "descirption",
"impactedServices": [
"59591948-d418-4bb9-af16-170d6b232b7d",
"daa0d66f-ad35-4396-b30d-70f0314c697a"
],
"tinyId": "2",
"message": "My Incident",
"status": "open",
"tags": ["hello"],
"createdAt": "2023-09-20T13:33:00.941Z",
"updatedAt": "2023-09-26T17:48:54.48Z",
"priority": "P3",
"ownerTeam": "",
"responders": [
{
"type": "team",
"id": "63374eee-0b03-42d4-bb8c-50d1fa64827c"
},
{
"type": "user",
"id": "ce544b61-7b35-43ea-89ee-a8750638d3a4"
},
{
"type": "user",
"id": "9ea8f86a-6648-46d6-a2fc-1a6eb5f739c8"
}
],
"extraProperties": {},
"links": {
"web": "https://mytestaccount.app.opsgenie.com/incident/detail/4a0c5e6d-b239-4cd9-a7e8-a5f880e99473",
"api": "https://api.opsgenie.com/v1/incidents/4a0c5e6d-b239-4cd9-a7e8-a5f880e99473"
},
"impactStartDate": "2023-09-20T13:33:00.941Z",
"actions": [],
"__impactedServices": [
{
"id": "59591948-d418-4bb9-af16-170d6b232b7d",
"name": "My Test Service",
"description": "This is for Opsgenie testing",
"teamId": "63374eee-0b03-42d4-bb8c-50d1fa64827c",
"tags": ["port", "devops", "ai"],
"links": {
"web": "https://mytestaccount.app.opsgenie.com/service/59591948-d418-4bb9-af16-170d6b232b7d/status",
"api": "https://api.opsgenie.com/v1/services/59591948-d418-4bb9-af16-170d6b232b7d"
},
"isExternal": false
},
{
"id": "daa0d66f-ad35-4396-b30d-70f0314c697a",
"name": "Port Outbound Service",
"description": "For outbound communications and integrations",
"teamId": "63374eee-0b03-42d4-bb8c-50d1fa64827c",
"tags": ["ui", "comment"],
"links": {
"web": "https://mytestaccount.app.opsgenie.com/service/daa0d66f-ad35-4396-b30d-70f0314c697a/status",
"api": "https://api.opsgenie.com/v1/services/daa0d66f-ad35-4396-b30d-70f0314c697a"
},
"isExternal": false
}
]
}
Alert response data
{
"seen": true,
"id": "580e9625-ecc7-42b0-8836-3d3637438bc4-169486700232",
"tinyId": "2",
"alias": "355f1681-f6e3-4355-a927-897cd8edaf8f_4d37bc8a-030b-4e8f-a230-aa429947253c",
"message": "Login Auth not working",
"status": "open",
"integration": "Default API",
"acknowledged": false,
"isSeen": true,
"tags": ["auth", "login"],
"snoozed": false,
"count": 1,
"lastOccurredAt": "2023-04-21T08:36:18.46Z",
"createdAt": "2023-04-21T08:36:18.46Z",
"updatedAt": "2023-08-11T10:41:16.533Z",
"source": "testuser@gmail.com",
"owner": "testuser@gmail.com",
"priority": "P3",
"teams": [],
"responders": [
{
"type": "user",
"id": "ce544b61-7b35-43ea-89ee-a8750638d3a4"
}
],
"report": {
"ackTime": 4852912663
},
"ownerTeamId": "",
"__relatedIncident": {
"id": "4a0c5e6d-b239-4cd9-a7e8-a5f880e99473",
"description": "descirption",
"impactedServices": [
"59591948-d418-4bb9-af16-170d6b232b7d",
"daa0d66f-ad35-4396-b30d-70f0314c697a"
],
"tinyId": "2",
"message": "My Incident",
"status": "open",
"tags": ["hello"],
"createdAt": "2023-09-20T13:33:00.941Z",
"updatedAt": "2023-09-26T17:48:54.48Z",
"priority": "P3",
"ownerTeam": "",
"responders": [
{
"type": "team",
"id": "63374eee-0b03-42d4-bb8c-50d1fa64827c"
},
{
"type": "user",
"id": "ce544b61-7b35-43ea-89ee-a8750638d3a4"
},
{
"type": "user",
"id": "9ea8f86a-6648-46d6-a2fc-1a6eb5f739c8"
}
],
"extraProperties": {},
"links": {
"web": "https://mytestaccount.app.opsgenie.com/incident/detail/4a0c5e6d-b239-4cd9-a7e8-a5f880e99473",
"api": "https://api.opsgenie.com/v1/incidents/4a0c5e6d-b239-4cd9-a7e8-a5f880e99473"
}
}
}
Mapping Result
The combination of the sample payload and the Ocean configuration generates the following Port entity:
Service entity in Port
{
"identifier": "Port-Outbound-Service",
"title": "Port Outbound Service",
"team": [],
"properties": {
"description": "For outbound communications and integrations",
"url": "https://mytestaccount.app.opsgenie.com/service/daa0d66f-ad35-4396-b30d-70f0314c697a/status",
"tags": ["communication", "channel"],
"oncallTeam": "Data Science Team",
"teamMembers": ["testuser@gmail.com", "devtester@gmail.com"],
"oncallUsers": ["testuser@gmail.com"],
"numOpenIncidents": 2
},
"relations": {},
"icon": "OpsGenie"
}
Incident entity in Port
{
"identifier": "4a0c5e6d-b239-4cd9-a7e8-a5f880e99473",
"blueprint": "opsGenieIncident",
"title": "My Incident",
"properties": {
"status": "open",
"responders": [
{
"type": "team",
"id": "63374eee-0b03-42d4-bb8c-50d1fa64827c"
},
{
"type": "user",
"id": "ce544b61-7b35-43ea-89ee-a8750638d3a4"
},
{
"type": "user",
"id": "9ea8f86a-6648-46d6-a2fc-1a6eb5f739c8"
}
],
"priority": "P3",
"tags": ["hello"],
"url": "https://mytestaccount.app.opsgenie.com/incident/detail/4a0c5e6d-b239-4cd9-a7e8-a5f880e99473",
"createdAt": "2023-09-20T13:33:00.941Z",
"updatedAt": "2023-09-26T17:48:54.48Z",
"description": "descirption"
},
"relations": {
"services": ["Port-Outbound-Service", "My-Test-Service"]
},
"icon": "OpsGenie"
}
Alert entity in Port
{
"identifier": "580e9625-ecc7-42b0-8836-3d3637438bc4-1694867002321",
"title": "Login Auth not working",
"team": [],
"properties": {
"status": "open",
"acknowledged": true,
"tags": ["auth", "login"],
"responders": [
{
"type": "user",
"id": "ce544b61-7b35-43ea-89ee-a8750638d3a4"
}
],
"integration": "Default API",
"priority": "P3",
"sourceName": "testuser@gmail.com",
"createdBy": "testuser@gmail.com",
"createdAt": "2023-09-16T12:23:22.321Z",
"updatedAt": "2023-09-26T17:51:00.346Z",
"count": 1
},
"relations": {
"relatedIncident": "4a0c5e6d-b239-4cd9-a7e8-a5f880e99473"
},
"icon": "OpsGenie"
}
Alternative installation via webhook
While the Ocean integration described above is the recommended installation method, you may prefer to use a webhook to ingest data from Opsgenie. If so, use the following instructions:
Webhook installation (click to expand)
In this example you are going to create a webhook integration between OpsGenie and Port, which will ingest alert entities.
Port configuration
Create the following blueprint definition:
OpsGenie alert blueprint
{
"identifier": "opsGenieAlert",
"description": "This blueprint represents an OpsGenie alert in our software catalog",
"title": "OpsGenie Alert",
"icon": "OpsGenie",
"schema": {
"properties": {
"description": {
"type": "string",
"title": "Description"
},
"lastChangeType": {
"type": "string",
"title": "Last Change Type",
"description": "The type of the last change made to the alert"
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"title": "Tags"
},
"responders": {
"type": "array",
"title": "Responders",
"description": "Responders to the alert"
},
"teams": {
"type": "array",
"items": {
"type": "string"
},
"title": "Teams",
"description": "IDs of teams assigned to the alert"
},
"priority": {
"type": "string",
"title": "Priority"
},
"sourceName": {
"type": "string",
"title": "Source Name",
"description": "Alert source name"
},
"sourceType": {
"type": "string",
"title": "Source Type",
"description": "Alert source type"
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {
"status": {
"title": "Status",
"calculation": "if .properties.lastChangeType == \"Close\" then \"Closed\" else \"Active\" end",
"type": "string",
"colorized": true,
"colors": {
"Closed": "green",
"Active": "red"
}
}
},
"relations": {}
}
Create the following webhook configuration using Port UI:
OpsGenie alert webhook configuration
-
Basic details tab - fill the following details:
- Title :
OpsGenie mapper
; - Identifier :
opsgenie_mapper
; - Description :
A webhook configuration to map OpsGenie alerts to Port
; - Icon :
OpsGenie
;
- Title :
-
Integration configuration tab - fill the following JQ mapping:
[
{
"blueprint": "opsGenieAlert",
"entity": {
"identifier": ".body.alert.alertId",
"title": ".body.alert.tinyId + \" - \" + .body.alert.message",
"properties": {
"description": ".body.alert.description",
"lastChangeType": ".body.action",
"priority": ".body.alert.priority",
"sourceName": ".body.source.name",
"sourceType": ".body.source.type",
"tags": ".body.alert.tags",
"responders": ".body.alert.responders",
"teams": ".body.alert.teams"
}
}
}
] -
Click Save at the bottom of the page.
Create a webhook in OpsGenie
- Go to OpsGenie;
- Select Settings;
- Click on Integrations under the Integrations section of the sidebar;
- Click on Add integration;
- In the search box, type Webhook and select the webhook option;
- Input the following details:
Name
- use a meaningful name such as Port Webhook;- Be sure to keep the "Enabled" checkbox checked;
- Check the "Add Alert Description to Payload" checkbox;
- Check the "Add Alert Details to Payload" checkbox;
- Add the following action triggers to the webhook by clicking on Add new action:
- If alert is snoozed in Opsgenie, post to url in Webhook;
- If alert's description is updated in Opsgenie, post to url in Webhook;
- If alert's message is updated in Opsgenie, post to url in Webhook;
- If alert's priority is updated in Opsgenie, post to url in Webhook;
- If a responder is added to the alert in Opsgenie, post to url in Webhook;
- if a user executes "Assign Ownership in Opsgenie, post to url in Webhook;
- if a tag is added to the alert in Opsgenie, post to url in Webhook;
- .if a tag is removed from the alert in Opsgenie, post to url in Webhook;
Webhook URL
- enter the value of theurl
key you received after creating the webhook configuration;
- Click Save integration
In order to view the different payloads and events available in Opsgenie webhooks, look here
Done! any change that happens to an OpsGenie alert (created, acknowledged, etc.) will trigger a webhook event that OpsGenie will send to the webhook URL provided by Port. Port will parse the events according to the mapping and update the catalog entities accordingly.
Let's Test It
This section includes a sample webhook event sent from OpsGenie when an alert is created. In addition, it includes the entity created from the event based on the webhook configuration provided in the previous section.
Payload
Here is an example of the payload structure sent to the webhook URL when an OpsGenie alert is created:
Webhook event payload
{
"source": {
"name": "web",
"type": "API"
},
"alert": {
"tags": ["tag1", "tag2"],
"teams": ["team1", "team2"],
"responders": ["recipient1", "recipient2"],
"message": "test alert",
"username": "username",
"alertId": "052652ac-5d1c-464a-812a-7dd18bbfba8c",
"source": "user@domain.com",
"alias": "aliastest",
"tinyId": "10",
"entity": "An example entity",
"createdAt": 1686916265415,
"updatedAt": 1686916266116,
"userId": "daed1180-0ce8-438b-8f8e-57e1a5920a2d",
"description": "Testing opsgenie alerts",
"priority": "P1"
},
"action": "Create",
"integrationId": "37c8f316-17c6-49d7-899b-9c7e540c048d",
"integrationName": "Port-Integration"
}
Mapping Result
The combination of the sample payload and the webhook configuration generates the following Port entity:
{
"identifier": "052652ac-5d1c-464a-812a-7dd18bbfba8c",
"title": "10 - test alert",
"blueprint": "opsGenieAlert",
"properties": {
"description": "Testing opsgenie alerts",
"lastChangeType": "Create",
"priority": "P1",
"sourceName": "web",
"sourceType": "API",
"tags": ["tag1", "tag2"],
"responders": ["recipient1", "recipient2"],
"teams": ["team1", "team2"]
},
"relations": {}
}
Ingest who is on-call
In this example we will create a blueprint for service
entities with an on-call
property that will be ingested directly from OpsGenie.
The examples below pull data from the OpsGenie REST Api, in a defined scheduled period using GitLab Pipelines or GitHub Workflows, and report the data to Port as a property to the service
blueprint.