Merge pull request #2525 from grafana/dev

Merge dev to main
This commit is contained in:
Michael Derynck 2023-07-13 14:56:08 -06:00 committed by GitHub
commit 3ec23afea0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
59 changed files with 1470 additions and 283 deletions

10
.github/CODEOWNERS vendored
View file

@ -4,4 +4,14 @@
CHANGELOG.md
/grafana-plugin @grafana/grafana-oncall-frontend
/docs @grafana/docs-gops
# `make docs` procedure is owned by @jdbaldry of @grafana/docs-squad.
/.github/workflows/update-make-docs.yml @jdbaldry
/.github/workflows/publish-technical-documentation-next.yml @jdbaldry
/.github/workflows/publish-technical-documentation-release.yml @jdbaldry
/docs/Makefile @jdbaldry
/docs/docs.mk @jdbaldry
/docs/make-docs @jdbaldry
/docs/variables.mk @jdbaldry

View file

@ -83,8 +83,9 @@ jobs:
# -e HUGO_REFLINKSERRORLEVEL=ERROR prevents merging broken refs with the downside
# that no refs to external content can be used as these refs will not resolve in the
# docs-base image.
# Use alternative image (dbd975af06) until make-docs 3.0.0 is rolled out everywhere.
run: |
docker run -v ${PWD}/docs/sources:/hugo/content/docs/oncall/latest -e HUGO_REFLINKSERRORLEVEL=ERROR --rm grafana/docs-base:latest /bin/bash -c 'make hugo'
docker run -v ${PWD}/docs/sources:/hugo/content/docs/oncall/latest -e HUGO_REFLINKSERRORLEVEL=ERROR --rm grafana/docs-base:dbd975af06 /bin/bash -c 'echo -e "---\\nredirectURL: /hugo/content/docs/oncall/latest/\\ntype: redirect\\nversioned: true\\n---\\n" > /hugo/content/docs/oncall/_index.md; make hugo'
lint-migrations-backend-mysql-rabbitmq:
name: "Lint database migrations"

27
.github/workflows/update-make-docs.yml vendored Normal file
View file

@ -0,0 +1,27 @@
name: Update `make docs` procedure
on:
schedule:
- cron: '0 7 * * 1-5'
jobs:
main:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Update procedure
if: github.repository != 'grafana/writers-toolkit'
run: |
curl -s -Lo docs/docs.mk https://raw.githubusercontent.com/grafana/writers-toolkit/main/docs/docs.mk
curl -s -Lo docs/make-docs https://raw.githubusercontent.com/grafana/writers-toolkit/main/docs/make-docs
if git diff --exit-code; then exit 0; fi
BRANCH="$(date +%Y-%m-%d)/update-make-docs"
git checkout -b "${BRANCH}"
git add .
git config --local user.email "bot@grafana.com"
git config --local user.name "grafanabot"
git commit -m "Update \`make docs\` procedure"
git push -v origin "refs/heads/${BRANCH}"
gh pr create --fill
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View file

@ -107,5 +107,5 @@ repos:
name: markdownlint
entry: markdownlint --fix --ignore grafana-plugin/node_modules --ignore grafana-plugin/dist --ignore docs **/*.md
- id: markdownlint
name: markdownlint - docs
entry: markdownlint --fix -c ./docs/.markdownlint.json ./docs/**/*.md
name: markdownlint - docs/sources
entry: markdownlint --fix --ignore README.md -c ./docs/.markdownlint.json ./docs/sources/**/*.md

View file

@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
## v1.3.11 (2023-07-13)
### Added
- Release new webhooks functionality by @mderynck @matiasb @maskin25 @teodosii @raphael-batte ([#1830](https://github.com/grafana/oncall/pull/1830))
### Changed
- Custom button webhooks are deprecated, they will be automatically migrated to new webhooks. ([#1830](https://github.com/grafana/oncall/pull/1830))
## v1.3.10 (2023-07-13)
### Added

View file

@ -4,5 +4,8 @@
"line_length": "160"
},
"MD025": false,
"MD036": false
"MD033": false,
"MD036": false,
"MD052": false,
"MD053": false
}

View file

@ -1,3 +1,5 @@
# The source of this file is https://raw.githubusercontent.com/grafana/writers-toolkit/main/docs/docs.mk.
# 4.0.0 (2023-06-06)
include variables.mk
-include variables.mk.local
@ -52,6 +54,11 @@ ifeq ($(origin DOC_VALIDATOR_IMAGE), undefined)
export DOC_VALIDATOR_IMAGE := grafana/doc-validator:latest
endif
# Container image used for vale linting.
ifeq ($(origin VALE_IMAGE), undefined)
export VALE_IMAGE := grafana/vale:latest
endif
# PATH-like list of directories within which to find projects.
# If all projects are checked out into the same directory, ~/repos/ for example, then the default should work.
ifeq ($(origin REPOS_PATH), undefined)
@ -91,17 +98,17 @@ docs-no-pull: make-docs
.PHONY: docs-debug
docs-debug: ## Run Hugo web server with debugging enabled. TODO: support all SERVER_FLAGS defined in website Makefile.
docs-debug: make-docs
WEBSITE_EXEC='hugo server --debug' $(PWD)/make-docs $(PROJECTS)
WEBSITE_EXEC='hugo server --bind 0.0.0.0 --port 3002 --debug' $(PWD)/make-docs $(PROJECTS)
.PHONY: doc-validator
doc-validator: ## Run docs-validator on the entire docs folder.
doc-validator: ## Run doc-validator on the entire docs folder.
doc-validator: make-docs
DOCS_IMAGE=$(DOC_VALIDATOR_IMAGE) $(PWD)/make-docs $(PROJECTS)
.PHONY: doc-validator/%
doc-validator/%: ## Run doc-validator on a specific path. To lint the path /docs/sources/administration, run 'make doc-validator/administration'.
doc-validator/%: make-docs
DOCS_IMAGE=$(DOC_VALIDATOR_IMAGE) DOC_VALIDATOR_INCLUDE=$(subst doc-validator/,,$@) $(PWD)/make-docs $(PROJECTS)
.PHONY: vale
vale: ## Run vale on the entire docs folder.
vale: make-docs
DOCS_IMAGE=$(VALE_IMAGE) $(PWD)/make-docs $(PROJECTS)
.PHONY: update
update: ## Fetch the latest version of this Makefile and the `make-docs` script from Writers' Toolkit.

View file

@ -1,5 +1,6 @@
#!/bin/sh
# The source of this file is https://raw.githubusercontent.com/grafana/writers-toolkit/main/docs/make-docs.
# 4.1.0 (2023-06-16)
set -ef
@ -8,9 +9,11 @@ readonly DOCS_HOST_PORT="${DOCS_HOST_PORT:-3002}"
readonly DOCS_IMAGE="${DOCS_IMAGE:-grafana/docs-base:latest}"
readonly DOC_VALIDATOR_INCLUDE="${DOC_VALIDATOR_INCLUDE:-.+\.md$}"
readonly DOC_VALIDATOR_SKIP_CHECKS="${DOC_VALIDATOR_SKIP_CHECKS:-^image-}"
readonly HUGO_REFLINKSERRORLEVEL="${HUGO_REFLINKSERRORLEVEL:-WARNING}"
readonly WEBSITE_EXEC="${WEBSITE_EXEC:-make server}"
readonly VALE_MINALERTLEVEL="${VALE_MINALERTLEVEL:-error}"
readonly WEBSITE_EXEC="${WEBSITE_EXEC:-make server-docs}"
# If set, the docs-base image will run a prebuild script that sets up Hugo mounts.
readonly WEBSITE_MOUNTS="${WEBSITE_MOUNTS:-}"
@ -59,23 +62,33 @@ fi
SOURCES_as_code='as-code-docs'
SOURCES_enterprise_metrics='backend-enterprise'
SOURCES_enterprise_metrics_='backend-enterprise'
SOURCES_grafana_cloud='cloud-docs'
SOURCES_grafana_cloud='website'
SOURCES_grafana_cloud_k6='k6-docs'
SOURCES_grafana_cloud_data_configuration_integrations='cloud-onboarding'
SOURCES_grafana_cloud_frontend_observability_faro_web_sdk='faro-web-sdk'
SOURCES_grafana_cloud_machine_learning='machine-learning'
SOURCES_helm_charts_mimir_distributed='mimir'
SOURCES_helm_charts_tempo_distributed='tempo'
SOURCES_opentelemetry='opentelemetry-docs'
SOURCES_plugins_grafana_splunk_datasource='splunk-datasource'
VERSIONS_as_code='UNVERSIONED'
VERSIONS_grafana_cloud='UNVERSIONED'
VERSIONS_grafana_cloud_k6='UNVERSIONED'
VERSIONS_grafana_cloud_data_configuration_integrations='UNVERSIONED'
VERSIONS_grafana_cloud_frontend_observability_faro_web_sdk='UNVERSIONED'
VERSIONS_grafana_cloud_machine_learning='UNVERSIONED'
VERSIONS_opentelemetry='UNVERSIONED'
VERSIONS_technical_documentation='UNVERSIONED'
VERSIONS_website='UNVERSIONED'
VERSIONS_writers_toolkit='UNVERSIONED'
PATHS_grafana_cloud='content/docs/grafana-cloud'
PATHS_helm_charts_mimir_distributed='docs/sources/helm-charts/mimir-distributed'
PATHS_helm_charts_tempo_distributed='docs/sources/helm-charts/tempo-distributed'
PATHS_mimir='docs/sources/mimir'
PATHS_tempo='docs/sources/tempo'
PATHS_website='content/docs'
# identifier STR
# Replace characters that are not valid in an identifier with underscores.
@ -138,6 +151,13 @@ proj_url() {
$1
POSIX_HERESTRING
if [ "${_project}" = 'website' ]; then
echo "http://localhost:${DOCS_HOST_PORT}/docs/"
unset _project _version
return
fi
if [ -z "${_version}" ] || [ "${_version}" = 'UNVERSIONED' ]; then
echo "http://localhost:${DOCS_HOST_PORT}/docs/${_project}/"
else
@ -165,14 +185,43 @@ proj_dst() {
$1
POSIX_HERESTRING
if [ "${_project}" = 'website' ]; then
echo '/hugo/content/docs'
unset _project _version
return
fi
if [ -z "${_version}" ] || [ "${_version}" = 'UNVERSIONED' ]; then
echo "/hugo/content/docs/${_project}"
else
echo "/hugo/content/docs/${_project}/${_version}"
fi
unset _project _version
}
# repo_path returns the host path to the project repository.
# It looks for the provided repository name in each of the paths specified in the REPOS_PATH environment variable.
repo_path() {
_repo="$1"
IFS=:
for lookup in ${REPOS_PATH}; do
if [ -d "${lookup}/${_repo}" ]; then
echo "${lookup}/${_repo}"
unset _path _repo
return
fi
done
unset IFS
echo "ERRR: could not find project '${_repo}' in any of the paths in REPOS_PATH '${REPOS_PATH}'." >&2
echo "NOTE: you must have a checkout of the project '${_repo}' at '${REPOS_PATH##:*}/${_repo}'." >&2
echo "NOTE: if you have cloned the repository into a directory with a different name, consider changing it to ${_repo}." >&2
unset _repo
exit 1
}
# proj_src returns the host path to content source for a project.
# It expects a complete project structure as input.
# It looks for the provided repository name in each of the paths specified in the REPOS_PATH environment variable.
@ -181,21 +230,10 @@ proj_src() {
$1
POSIX_HERESTRING
IFS=:
for lookup in ${REPOS_PATH}; do
if [ -d "${lookup}/${_repo}" ]; then
echo "${lookup}/${_repo}/${_path}"
unset _path _repo
return
fi
done
unset IFS
_repo="$(repo_path "${_repo}")"
echo "${_repo}/${_path}"
echo "ERRR: could not find project '${_repo}' in any of the paths in REPOS_PATH '${REPOS_PATH}'." >&2
echo "NOTE: you must have a checkout of the project '${_repo}' at '${REPOS_PATH##:*}/${_repo}'." >&2
echo "NOTE: if you have cloned the repository into a directory with a different name, consider changing it to ${_repo}." >&2
unset _path _repo
exit 1
}
# proj_canonical returns the canonical absolute path partial URI for a project.
@ -205,11 +243,19 @@ proj_canonical() {
$1
POSIX_HERESTRING
if [ "${_project}" = 'website' ]; then
echo '/docs'
unset _project _version
return
fi
if [ -z "${_version}" ] || [ "${_version}" = 'UNVERSIONED' ]; then
echo "/docs/${_project}"
else
echo "/docs/${_project}/${_version}"
fi
unset _project _version
}
@ -262,6 +308,19 @@ url_src_dst_vers="$(url_src_dst_vers "$@")"
volumes=""
redirects=""
for arg in "$@"; do
IFS=: read -r _project _ _repo _ <<POSIX_HERESTRING
${arg}
POSIX_HERESTRING
if [ "${_project}" = website ]; then
_repo="$(repo_path website)"
volumes="--volume=${_repo}/config:/hugo/config"
volumes="${volumes} --volume=${_repo}/layouts/partials:/hugo/layouts/partials"
volumes="${volumes} --volume=${_repo}/layouts/shortcodes:/hugo/layouts/shortcodes"
fi
unset _project _repo
done
for x in ${url_src_dst_vers}; do
IFS='^' read -r _url _src _dst _ver <<POSIX_HERESTRING
$x
@ -296,64 +355,96 @@ IFS=':' read -r image _ <<POSIX_HERESTRING
${DOCS_IMAGE}
POSIX_HERESTRING
if [ "${image}" = "grafana/doc-validator" ]; then
echo
"${PODMAN}" run \
--init \
--interactive \
--name "${DOCS_CONTAINER}" \
--platform linux/amd64 \
--rm \
--tty \
${volumes} \
"${DOCS_IMAGE}" \
--skip-image-validation \
--include="${DOC_VALIDATOR_INCLUDE}" \
/hugo/content/docs \
"$(proj_canonical "$(new_proj "$1")")"
else
cat <<EOF >/tmp/make-docs-entrypoint
case "${image}" in
'grafana/doc-validator')
proj="$(new_proj "$1")"
echo
"${PODMAN}" run \
--init \
--interactive \
--name "${DOCS_CONTAINER}" \
--platform linux/amd64 \
--rm \
--tty \
${volumes} \
"${DOCS_IMAGE}" \
"--include=${DOC_VALIDATOR_INCLUDE}" \
"--skip-checks=${DOC_VALIDATOR_SKIP_CHECKS}" \
/hugo/content/docs \
"$(proj_canonical "${proj}")" | sed "s#$(proj_dst "${proj}")#sources#"
;;
'grafana/vale')
proj="$(new_proj "$1")"
echo
"${PODMAN}" run \
--init \
--interactive \
--name "${DOCS_CONTAINER}" \
--platform linux/amd64 \
--rm \
--tty \
${volumes} \
"${DOCS_IMAGE}" \
"--minAlertLevel=${VALE_MINALERTLEVEL}" \
--config=/etc/vale/.vale.ini \
--output=line \
/hugo/content/docs | sed "s#$(proj_dst "${proj}")#sources#"
;;
*)
tempfile="$(mktemp -t make-docs.XXX)"
cat <<EOF >"${tempfile}"
#!/usr/bin/env bash
for redirect in ${redirects}; do
IFS='^' read -r path ver <<<"\${redirect}"
echo -e "---\\nredirectURL: \"\${path/\/hugo\/content/}\"\\ntype: redirect\\n---\\n" > "\${path/\${ver}/_index.md}"
if [[ -n "${WEBSITE_MOUNTS}" ]]; then
unset WEBSITE_SKIP_MOUNTS
fi
echo -e "---\\nredirectURL: \"\${path/\/hugo\/content/}\"\\ntype: redirect\\nversioned: true\\n---\\n" > "\${path/\${ver}/_index.md}"
done
for x in "${url_src_dst_vers}"; do
IFS='^' read -r _ _ dst _ <<<"\${x}"
while [[ -n "\${dst}" ]]; do
touch "\${dst}/_index.md"
dst="\${dst%/*}"
done
done
if [[ -n "${WEBSITE_MOUNTS}" ]]; then
unset WEBSITE_SKIP_MOUNTS
fi
${WEBSITE_EXEC}
EOF
chmod +x /tmp/make-docs-entrypoint
volumes="${volumes} --volume=/tmp/make-docs-entrypoint:/entrypoint"
readonly volumes
chmod +x "${tempfile}"
volumes="${volumes} --volume=$(realpath "${tempfile}"):/entrypoint"
readonly volumes
echo
echo "Documentation will be served at the following URLs:"
for x in ${url_src_dst_vers}; do
IFS='^' read -r url _ _ <<POSIX_HERESTRING
echo
echo "Documentation will be served at the following URLs:"
for x in ${url_src_dst_vers}; do
IFS='^' read -r url _ _ <<POSIX_HERESTRING
$x
POSIX_HERESTRING
if [ -n "${url}" ]; then
echo " ${url}"
fi
done
if [ -n "${url}" ]; then
if [ "${_url}" != "arbitrary" ]; then
echo " ${url}"
fi
fi
done
echo
"${PODMAN}" run \
--env "HUGO_REFLINKSERRORLEVEL=${HUGO_REFLINKSERRORLEVEL}" \
--init \
--interactive \
--name "${DOCS_CONTAINER}" \
--platform linux/amd64 \
--publish "${DOCS_HOST_PORT}:3002" \
--publish "3003:3003" \
--rm \
--tty \
${volumes} \
"${DOCS_IMAGE}" \
/entrypoint
fi
echo
"${PODMAN}" run \
--env "HUGO_REFLINKSERRORLEVEL=${HUGO_REFLINKSERRORLEVEL}" \
--init \
--interactive \
--name "${DOCS_CONTAINER}" \
--platform linux/amd64 \
--publish "${DOCS_HOST_PORT}:3002" \
--publish "3003:3003" \
--rm \
--tty \
${volumes} \
"${DOCS_IMAGE}" \
/entrypoint
;;
esac

View file

@ -11,7 +11,7 @@ Often alerts from monitoring systems need to be sent to different escalation cha
## Routes
Routes are used to determine which escalation chain should be used for a specific alert
group. A route's ["Routing Templates"]({{< relref "jinja2-templating#routing-template" >}})
group. A route's ["Routing Templates"][routing-template]
are evaluated for each alert and **the first matching route** is used to determine the
escalation chain and chatops channels.
@ -27,7 +27,7 @@ escalation chain and chatops channels.
2. Click **Add route** button to create a new route
3. Click **Edit** button to edit `Routing Template`. The routing template must evaluate to `True` for it to apply
4. Select channels in **Publish to Chatops** section
> **Note:** If **Publish to Chatops** section does not exist, connect Chatops integrations first, see more in [docs]({{< relref notify >}})
> **Note:** If **Publish to Chatops** section does not exist, connect Chatops integrations first, see more in [docs][notify]
5. Select **Escalation Chain** from the list
6. If **Escalation Chain** does not exist, click **Add new escalation chain** button to create a new one, it will open in a new tab.
7. Once created, **Reload list**, and select the new escalation chain
@ -45,7 +45,7 @@ Users can create escalation chains to configure different type of escalation wor
For example, you can create a chain that will notify on-call users with high priopity, and
another chain that will only send a message into a Slack channel.
Escalation chains determine Who and When to notify. [How to notify]({{< relref notify >}}) is set by the user, based on their own preferences.
Escalation chains determine Who and When to notify. [How to notify][notify] is set by the user, based on their own preferences.
### Types of escalation steps
@ -59,14 +59,9 @@ from an on-call schedule.
* `Notify whole slack channel` - send a notification to a slack channel (not recommended
to use as it will spam the channel).
* `Notify Slack User Group` - send a notification to a slack user group.
* `Trigger outgoing webhook` - trigger an [outgoing webhook]({{< relref outgoing-webhooks
>}}).
<https://en.wikipedia.org/>
* `Trigger outgoing webhook` - trigger an [outgoing webhook][outgoing-webhooks].
* `Notify users one by one (round robin)` - each notification will be sent to a group of
users one by one, in sequential order in [round robin fashion](<https://en.wikipedia.org/>
wiki/Round-robin_item_allocation).
users one by one, in sequential order in [round robin fashion](https://en.wikipedia.org/wiki/Round-robin_item_allocation).
* `Continue escalation if current time is in range` - continue escalation only if current
time is in specified range. It will wait for the specfied time to continue escalation.
Useful when you want to get escalation only during working hours
@ -87,7 +82,7 @@ User can configure two types of personal notification chains:
In the escalation step, user can select which type of notification to use.
Check more information on [Personal Notification Preferences]({{< relref notify >}}) page.
Check more information on [Personal Notification Preferences][notify] page.
### Manage Escalation Chains
@ -102,3 +97,14 @@ Check more information on [Personal Notification Preferences]({{< relref notify
> **Important:** Linked Integrations and Routes are displayed in the right panel. Any change in the Escalation Chain will
affect all linked Integrations and Routes.
{{% docs/reference %}}
[notify]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/notify"
[notify]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/notify"
[outgoing-webhooks]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/outgoing-webhooks"
[outgoing-webhooks]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/outgoing-webhooks"
[routing-template]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/jinja2-templating#routing-template"
[routing-template]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/jinja2-templating#routing-template"
{{% /docs/reference %}}

View file

@ -30,21 +30,21 @@ Grafana OnCall is available both in Grafana Cloud and Grafana Open Source.
OnCall is available in Grafana Cloud automatically:
1. Create or log in into [Grafana Cloud account](https://grafana.com/auth/sign-up/create-user)
1. Create or log in into [Grafana Cloud account](/auth/sign-up/create-user)
2. Sign in to your Grafana stack
3. Choose **Alerts and IRM** from the left menu
4. Click **OnCall** to access Grafana OnCall
Otherwise you'll need to install [Open Source Grafana OnCall]({{< relref "../open-source" >}}) on your own.
Otherwise you'll need to install [Open Source Grafana OnCall][open-source] on your own.
## How to configure Grafana OnCall
* Users with [Admin role]({{< relref "user-and-team-management" >}}) can configure Alert rules (Integrations, Routes, etc)
* Users with [Admin role][user-and-team-management] can configure Alert rules (Integrations, Routes, etc)
to define **when and which users to notify**
* OnCall users with [Editor role]({{< relref "user-and-team-management" >}}) can work with Alerts Groups and set up personal settings,
* OnCall users with [Editor role][user-and-team-management] can work with Alerts Groups and set up personal settings,
e.g. **how to notify**.
> **Note:** If your role is **Editor**, you can skip to [**Learn Alert Workflow**]({{< relref "#learn-about-the-alert-workflow" >}}) section
> **Note:** If your role is **Editor**, you can skip to [**Learn Alert Workflow**](#learn-about-the-alert-workflow) section
of this doc
## Get alerts into Grafana OnCall and configure rules
@ -73,19 +73,19 @@ send a demo alert.
4. Acknowledge and resolve the test alert group
For more information on Grafana OnCall integrations and further configuration guidance, refer to
[Grafana OnCall integrations]({{< relref "../integrations" >}})
[Grafana OnCall integrations][integrations]
### Review and modify alert templates
Review and customize templates to interpret monitoring alerts and minimize noise. Group alerts, enable auto-resolution,
customize visualizations and notifications by extracting data from alerts. See more details in the
[Jinja2 templating]({{< relref "../jinja2-templating" >}}) section.
[Jinja2 templating][jinja2-templating] section.
### Configure scalation Chains
Escalation chains are a set of steps that define who to notify, and when.
See more details in the [Escalation Chains]({{< relref "../escalation-chains-and-routes#escalation-chains" >}}) section.
See more details in the [Escalation Chains][escalation-chains] section.
Escalation Chains are customizable automated alert routing steps that enable you to specify who is notified for a certain
alert. In addition to escalation chains, you can configure Routes to send alerts to different escalation chains depending
@ -106,14 +106,14 @@ Alerts from this integration will now follow the escalation steps configured in
For more information on Escalation Chains and more ways to customize them, refer to
[Configure and manage Escalation Chains]({{< relref "escalation-chains-and-routes" >}})
[Configure and manage Escalation Chains][escalation-chains-and-routes]
Routes define which messenger channels and escalation chains to use for notifications. See more details in
the [Routes]({{< relref "../escalation-chains-and-routes#routes" >}}) section.
the [Routes][routes] section.
### Learn about the Alert Workflow
* All Alerts in OnCall are grouped into Alert Groups ([read more about Grouping ID]({{< relref "../jinja2-templating" >}})).
* All Alerts in OnCall are grouped into Alert Groups ([read more about Grouping ID][jinja2-templating]).
An Alert Group can have the following, mutually exclusive states:
* **Firing:** Once Alert Group is registered, Escalation Policy associated with it is getting started.
Escalation policy will work while Alert Group is in this status.
@ -150,7 +150,7 @@ Personal notification policies determine how a user is notified for a certain ty
phone call, Slack mentions, or mobile push notification. Administrators can configure how users receive notifications
for certain types of alerts.
For more information on personal notification policies, refer to
[Manage users and teams for Grafana OnCall]({{< relref "user-and-team-management" >}})
[Manage users and teams for Grafana OnCall][user-and-team-management]
To configure users personal notification policies:
@ -174,9 +174,9 @@ To configure Slack for Grafana OnCall:
6. Ensure users verify their Slack accounts in their user profile in Grafana OnCall.
For further instruction on connecting to your Slack workspace, refer to
[Slack integration for Grafana OnCall]({{< relref "../notify/slack/" >}})
[Slack integration for Grafana OnCall][slack]
Grafana OnCall also supports other ChatOps integration like [Microsoft Teams and Telegram]({{< relref "../notify" >}}).
Grafana OnCall also supports other ChatOps integration like [Microsoft Teams and Telegram][notify].
### Add your on-call schedule
@ -189,4 +189,36 @@ To integrate your on-call calendar with Grafana OnCall:
2. Provide a schedule name.
3. Configure the rest of the schedule settings and click Create Schedule
[More information on on-call schedules.]({{< relref "on-call-schedules" >}})
[More information on on-call schedules.][on-call-schedules]
{{% docs/reference %}}
[escalation-chains-and-routes]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/escalation-chains-and-routes"
[escalation-chains-and-routes]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/escalation-chains-and-routes"
[escalation-chains]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/escalation-chains-and-routes#escalation-chains"
[escalation-chains]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/escalation-chains-and-routes#escalation-chains"
[integrations]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/integrations"
[integrations]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/integrations"
[jinja2-templating]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/jinja2-templating"
[jinja2-templating]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/jinja2-templating"
[notify]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/notify"
[notify]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/notify"
[on-call-schedules]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/on-call-schedules"
[on-call-schedules]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/on-call-schedules"
[open-source]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/open-source"
[open-source]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/open-source"
[routes]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/escalation-chains-and-routes#routes"
[routes]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/escalation-chains-and-routes#routes"
[slack]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/notify/slack"
[slack]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/notify/slack"
[user-and-team-management]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/user-and-team-management"
[user-and-team-management]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/user-and-team-management"
{{% /docs/reference %}}

View file

@ -246,7 +246,7 @@ Resource IDs are used a lot in insight logs. You can find them in web ui (exampl
3. The URL looks like `https://<YOUR_STACK_SLUG>/a/grafana-oncall-app/integrations/C5VXMIFKKP67K`.
4. Integration ID is `C5VXMIFKKP67K`.
Alternatively you can find resource ID using public [API](https://grafana.com/docs/oncall/latest/oncall-api-reference/) or browser dev tools.
Alternatively you can find resource ID using public [API][oncall-api-reference] or browser dev tools.
Actions performed by user:
@ -277,3 +277,8 @@ Actions performed with slack chatops integration:
```logql
{instance_type="oncall"} | logfmt | __error__=`` | action_type = `chat_ops` and chat_ops_type=`slack`
```
{{% docs/reference %}}
[oncall-api-reference]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/oncall-api-reference"
[oncall-api-reference]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/oncall-api-reference"
{{% /docs/reference %}}

View file

@ -18,20 +18,20 @@ An "Integration" is a main entry point for alerts being consumed by Grafana OnCa
Integrations receive alerts on a unique API URL, interprets them using a set of templates tailored for the monitoring system, and starts
escalations.
Read more about Jinja2 templating used in OnCall [here]({{< relref "../jinja2-templating" >}}).
Read more about Jinja2 templating used in OnCall [here][jinja2-templating].
## Learn Alert Flow Within Integration
1. An Alert is received on an integration's **Unique URL** as an HTTP POST request with a JSON payload (or via
[e-mail]({{< relref "inbound-email" >}}), for inbound e-mail integrations)
1. Routing is determined for the incoming alert, by applying the [Routing Template]({{< relref "jinja2-templating#routing-template" >}})
1. Alert Grouping is determined based on [Grouping Id Template]({{< relref "jinja2-templating#behavioral-template" >}})
1. Routing is determined for the incoming alert, by applying the [Routing Template][routing-template]
1. Alert Grouping is determined based on [Grouping Id Template][behavioral-template]
1. An Alert Group may be acknowledged or resolved with status `_ by source` based on
[Behaviour Templates]({{< relref "jinja2-templating#behavioral-template" >}})
[Behaviour Templates][behavioral-template]
1. The Alert Group is available in Web, and can be published to messengers, based on the Route's **Publish to Chatops** configuration.
It is rendered using [Appearance Templates]({{< relref "jinja2-templating#appearance-template" >}})
It is rendered using [Appearance Templates][appearance-template]
1. The Alert Group is escalated to uers based on the Escalation Chains selected for the Route
1. Users can perform actions listed in [Learn Alert Workflow]({{< relref "get-started#learn-alert-workflow" >}}) section
1. Users can perform actions listed in [Learn Alert Workflow][learn-alert-workflow] section
## Configure and manage integrations
@ -43,7 +43,7 @@ describe how to configure and customize your integrations to ensure alerts are t
To configure an integration for Grafana OnCall:
1. In Grafana OnCall, navigate to the **Integrations** tab and click **+ New integration**.
1. Select an integration type from the [list of available integrations]({{< relref "#list-of-available-integrations" >}}).
1. Select an integration type from the [list of available integrations](#list-of-available-integrations).
If the integration you want isnt listed, then select **Webhook**.
1. Fill in a title and a description for your integration, assign it to a team, and click **Create Integration**.
1. The Integration page will open. Here you will see details about the Integration.
@ -54,13 +54,13 @@ Click the **How to connect** link for more information.
### Complete the integration configuration
- Review and customise grouping, autoresolution, autoacknowledge, etc [templates]({{< relref "../jinja2-templating" >}})
- Review and customise grouping, autoresolution, autoacknowledge, etc [templates][jinja2-templating]
if you want to customise alert behaviour for your team
- Review and customise [other templates]({{< relref "../jinja2-templating" >}}) to change how alert groups are displayed
- Review and customise [other templates][jinja2-templating] to change how alert groups are displayed
in different parts of Grafana OnCall: UI, messengers, emails, notifications, etc.
- Add routes to your integration to route alerts to different users and teams based on labels or other data
- Connect your escalation chains to routes to notify the right people, at the right time
- Learn [how to start Maintenance Mode]({{< relref "#maintenance-mode" >}}) for an integration
- Learn [how to start Maintenance Mode](#maintenance-mode) for an integration
- Send demo alerts to an integration to make sure routes, templates, and escalations, are working as expected. Consider using
`Debug Maintenance mode` to avoid sending real notifications to your team
@ -103,7 +103,7 @@ More specific instructions can be found in a specific integration's documentatio
"Integration templates" are Jinja2 templates which are applied to each alert to define it's rendering and behaviour.
Read more in [Templates guide]({{< relref jinja2-templating>}})
Read more in [Templates guide][jinja2-templating]
For templates editor:
@ -143,3 +143,20 @@ To edit the name of an integration:
## List of available integrations
{{< section >}}
{{% docs/reference %}}
[appearance-template]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/jinja2-templating#appearance-template"
[appearance-template]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/jinja2-templating#appearance-template"
[behavioral-template]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/jinja2-templating#behavioral-template"
[behavioral-template]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/jinja2-templating#behavioral-template"
[jinja2-templating]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/jinja2-templating"
[jinja2-templating]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/jinja2-templating"
[learn-alert-workflow]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/get-started#learn-alert-workflow"
[learn-alert-workflow]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/get-started#learn-alert-workflow"
[routing-template]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/jinja2-templating#routing-template"
[routing-template]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/jinja2-templating#routing-template"
{{% /docs/reference %}}

View file

@ -15,7 +15,7 @@ weight: 300
# Alertmanager integration for Grafana OnCall
> You must have the [role of Admin]({{< relref "user-and-team-management" >}}) to be able to create integrations in Grafana OnCall.
> You must have the [role of Admin][user-and-team-management] to be able to create integrations in Grafana OnCall.
The Alertmanager integration handles alerts from [Prometheus Alertmanager](https://prometheus.io/docs/alerting/latest/alertmanager/).
This integration is the recommended way to send alerts from Prometheus deployed in your infrastructure, to Grafana OnCall.
@ -59,7 +59,7 @@ receivers:
## Complete the Integration Configuration
Complete configuration by setting routes, templates, maintenances, etc. Read more in
[this section]({{< relref "../../integrations/#complete-the-integration-configuration" >}})
[this section][complete-the-integration-configuration]
## Configuring OnCall Heartbeats (optional)
@ -111,5 +111,12 @@ Add receiver configuration to `prometheus.yaml` with the **OnCall Heartbeat URL*
webhook_configs:
- url: https://oncall-dev-us-central-0.grafana.net/oncall/integrations/v1/alertmanager/1234567890/heartbeat/
send_resolved: false
```
```
{{% docs/reference %}}
[user-and-team-management]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/user-and-team-management"
[user-and-team-management]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/user-and-team-management"
[complete-the-integration-configuration]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/integrations#complete-the-integration-configuration"
[complete-the-integration-configuration]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/integrations#complete-the-integration-configuration"
{{% /docs/reference %}}

View file

@ -18,7 +18,7 @@ weight: 500
The Amazon SNS integration for Grafana OnCall handles ticket events sent from Amazon SNS webhooks.
The integration provides grouping, auto-acknowledge and auto-resolve logic via customizable alert templates.
> You must have the [role of Admin]({{< relref "user-and-team-management" >}}) to be able to create integrations
> You must have the [role of Admin][user-and-team-management] to be able to create integrations
in Grafana OnCall.
## Configuring Grafana OnCall to Receive Alerts from Amazon SNS
@ -35,3 +35,8 @@ in Grafana OnCall.
2. Open this topic, then create a new subscription
3. Choose the protocol HTTPS
4. Add the **OnCall Integration URL** to the Amazon SNS Endpoint
{{% docs/reference %}}
[user-and-team-management]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/user-and-team-management"
[user-and-team-management]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/user-and-team-management"
{{% /docs/reference %}}

View file

@ -18,7 +18,7 @@ weight: 500
The AppDynamics integration for Grafana OnCall handles health rule violation events sent from AppDynamics actions.
The integration provides grouping and auto-resolve logic via customizable alert templates.
> You must have the [role of Admin]({{< relref "user-and-team-management" >}}) to be able to create integrations in Grafana OnCall.
> You must have the [role of Admin][user-and-team-management] to be able to create integrations in Grafana OnCall.
## Configuring Grafana OnCall to Receive Alerts from AppDynamics
@ -105,4 +105,12 @@ Grafana OnCall provides grouping and auto-resolve logic for the AppDynamics inte
## Complete the Integration Configuration
Complete configuration by setting routes, templates, maintenances, etc. Read more in
[this section]({{< relref "../../integrations/#complete-the-integration-configuration" >}})
[this section][complete-the-integration-configuration]
{{% docs/reference %}}
[complete-the-integration-configuration]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/integrations#complete-the-integration-configuration"
[complete-the-integration-configuration]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/integrations#complete-the-integration-configuration"
[user-and-team-management]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/user-and-team-management"
[user-and-team-management]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/user-and-team-management"
{{% /docs/reference %}}

View file

@ -18,7 +18,7 @@ weight: 500
The Datadog integration for Grafana OnCall handles ticket events sent from Datadog webhooks.
The integration provides grouping, auto-acknowledge and auto-resolve logic via customizable alert templates.
> You must have the [role of Admin]({{< relref "user-and-team-management" >}}) to be able to create integrations in Grafana OnCall.
> You must have the [role of Admin][user-and-team-management] to be able to create integrations in Grafana OnCall.
## Configuring Grafana OnCall to Receive Alerts from Datadog
@ -36,3 +36,8 @@ The integration provides grouping, auto-acknowledge and auto-resolve logic via c
5. Navigate to the Events page from the sidebar to send the test alert
6. Type @webhook-grafana-oncall-alerts test alert
7. Click the post button
{{% docs/reference %}}
[user-and-team-management]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/user-and-team-management"
[user-and-team-management]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/user-and-team-management"
{{% /docs/reference %}}

View file

@ -18,7 +18,7 @@ weight: 500
The ElastAlert integration for Grafana OnCall handles ticket events sent from ElastAlert webhooks.
The integration provides grouping, auto-acknowledge and auto-resolve logic via customizable alert templates.
> You must have the [role of Admin]({{< relref "user-and-team-management" >}}) to be able to create integrations in Grafana OnCall.
> You must have the [role of Admin][user-and-team-management] to be able to create integrations in Grafana OnCall.
## Configuring Grafana OnCall to Receive Alerts from ElastAlert
@ -74,3 +74,8 @@ Add the following rule to ElastAlert
alert_text: elastalert is still running
alert_text_type: alert_text_only
```
{{% docs/reference %}}
[user-and-team-management]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/user-and-team-management"
[user-and-team-management]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/user-and-team-management"
{{% /docs/reference %}}

View file

@ -18,7 +18,7 @@ weight: 500
The Fabric integration for Grafana OnCall handles ticket events sent from Fabric webhooks.
The integration provides grouping, auto-acknowledge and auto-resolve logic via customizable alert templates.
> You must have the [role of Admin]({{< relref "user-and-team-management" >}}) to be able to create integrations in Grafana OnCall.
> You must have the [role of Admin][user-and-team-management] to be able to create integrations in Grafana OnCall.
## Configuring Grafana OnCall to Receive Alerts from Fabric
@ -35,3 +35,8 @@ The integration provides grouping, auto-acknowledge and auto-resolve logic via c
4. Enter URL: **OnCall Integration URL**
5. Click Verify
6. Choose "SEND IMPACT CHANGE ALERTS" and "ALSO SEND NON-FATAL ALERTS"
{{% docs/reference %}}
[user-and-team-management]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/user-and-team-management"
[user-and-team-management]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/user-and-team-management"
{{% /docs/reference %}}

View file

@ -27,7 +27,7 @@ You must have an Admin role to create integrations in Grafana OnCall.
## Grouping and auto-resolve
Alert groups will be grouped by email subject and auto-resolved if the email message text equals "OK".
This behaviour can be modified via [custom templates]({{< relref "jinja2-templating" >}}).
This behaviour can be modified via [custom templates][jinja2-templating].
Alerts from Inbound Email integration have the following payload:
@ -38,3 +38,8 @@ Alerts from Inbound Email integration have the following payload:
"sender": "<your_email_sender_address>"
}
```
{{% docs/reference %}}
[jinja2-templating]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/jinja2-templating"
[jinja2-templating]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/jinja2-templating"
{{% /docs/reference %}}

View file

@ -8,6 +8,7 @@ keywords:
- Alerts
- Notifications
- on-call
- webhooks
- Jira
title: Jira
weight: 500
@ -18,7 +19,7 @@ weight: 500
The Jira integration for Grafana OnCall handles issue events sent from Jira webhooks.
The integration provides grouping, auto-acknowledge and auto-resolve logic via customizable alert templates.
> You must have the [role of Admin]({{< relref "user-and-team-management" >}}) to be able to create integrations in Grafana OnCall.
> You must have the [role of Admin][user-and-team-management] to be able to create integrations in Grafana OnCall.
## Configuring Grafana OnCall to Receive Alerts from Jira
@ -49,3 +50,128 @@ Grafana OnCall provides grouping, auto-acknowledge and auto-resolve logic for th
- Alert groups are auto-resolved when the issue is closed or deleted
To customize this behaviour, consider modifying alert templates in integration settings.
## Configuring Grafana OnCall to send data to Jira
Grafana OnCall can automatically create and resolve issues in Jira via [outgoing webhooks]({{< relref "_index.md" >}}).
This guide provides example webhook configurations for common use cases, as well as information on how to set up a user in Jira to be used by Grafana OnCall.
### Prerequisites
1. Create a new user in Jira to be used by Grafana OnCall. [Obtain an API token for the user](https://id.atlassian.com/manage-profile/security/api-tokens),
these credentials will be used to communicate with Jira REST API.
2. Make sure the user has appropriate permissions to create and update issues in Jira.
### Create issues in Jira
The steps below describe how to create an outgoing webhook in Grafana OnCall that will allow to automatically create
issues in Jira from Grafana OnCall alert groups.
Create a new Outgoing Webhook in Grafana OnCall, and configure it as follows:
- Trigger type: `Alert Group Created`
- Integrations: Select integrations that will trigger the webhook
- HTTP method: `POST`
- Webhook URL:
```text
https://<INSTANCE>.atlassian.net/rest/api/2/issue
```
Replace `<INSTANCE>` with your Jira instance.
- Username: Email of the [Jira user](#prerequisites)
- Password: API token of the [Jira user](#prerequisites)
Use the following JSON template as webhook data:
```json
{
"fields": {
"project": {
"key": "<PROJECT_KEY>"
},
"issuetype": {
"name": "[System] Incident"
},
"summary": "{{alert_group.title}}",
"description": "This issue is created automatically by Grafana OnCall. Alert group {{alert_group.id}}: {{alert_group.permalinks.web}}"
}
}
```
Replace `<PROJECT_KEY>` with the key of the project in Jira.
>**Note**: You might want to use a different `issuetype.name` depending on your Jira instance configuration and use case.
### Resolve issues in Jira
The steps below describe how to create an outgoing webhook in Grafana OnCall that will allow to automatically resolve
issues in Jira when an alert group is resolved in Grafana OnCall.
- Trigger type: `Resolved`
- Integrations: Select integrations that will trigger the webhook
- HTTP method: `POST`
- Webhook URL:
```text
https://<INSTANCE>.atlassian.net/rest/api/2/issue/{{responses.<WEBHOOK_ID>.key}}/transitions
```
Replace `<INSTANCE>` with your Jira instance, and `<WEBHOOK_ID>` with the ID of the [webhook used for creating issues](#create-issues-in-jira).
- Username: Email of the [Jira user](#prerequisites)
- Password: API token of the [Jira user](#prerequisites)
Use the following JSON template as webhook data:
```json
{
"transition": {
"id": "<TRANSITION_ID>"
},
"fields": {
"resolution": {
"name": "Done"
}
},
"update": {
"comment": [
{
"add": {
"body": "Resolved by Grafana OnCall.",
"public": false
}
}
]
}
}
```
Replace `<TRANSITION_ID>` with the ID of the transition specific to your Jira instance.
See [here](https://community.atlassian.com/t5/Jira-questions/How-to-fine-transition-ID-of-JIRA/qaq-p/1207483#M385834)
for more info on how to find the transition ID in Jira UI, or use the
[REST API endpoint](https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issues/#api-rest-api-3-issue-issueidorkey-transitions-get)
to get the list of available transitions.
### Advanced usage
The examples above describe how to create outgoing webhooks in Grafana OnCall that will allow to automatically create and resolve issues in Jira.
Consider modifying example templates to fit your use case (e.g. to include more information on alert groups).
Refer to [outgoing webhooks documentation]({{< relref "_index.md" >}}) for more information on available template variables and webhook configuration.
For more information on Jira REST API, refer to [Jira REST API documentation](https://developer.atlassian.com/cloud/jira/platform/rest/v2/api-group-issues).
{{% docs/reference %}}
[user-and-team-management]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/user-and-team-management"
[user-and-team-management]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/user-and-team-management"
{{% /docs/reference %}}

View file

@ -18,7 +18,7 @@ weight: 500
The Kapacitor integration for Grafana OnCall handles ticket events sent from Kapacitor webhooks.
The integration provides grouping, auto-acknowledge and auto-resolve logic via customizable alert templates.
> You must have the [role of Admin]({{< relref "user-and-team-management" >}}) to be able to create integrations in Grafana OnCall.
> You must have the [role of Admin][user-and-team-management] to be able to create integrations in Grafana OnCall.
## Configuring Grafana OnCall to Receive Alerts from Kapacitor
@ -59,3 +59,8 @@ To send an alert from Kapacitor, you can follow these steps:
When the condition defined in the TICKscript is met, Kapacitor will trigger the alert and send
a POST request to the specified webhook URL with the necessary information. Make sure your webhook
endpoint is configured to receive and process the incoming alerts from Kapacitor.
{{% docs/reference %}}
[user-and-team-management]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/user-and-team-management"
[user-and-team-management]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/user-and-team-management"
{{% /docs/reference %}}

View file

@ -18,7 +18,7 @@ weight: 500
The New Relic integration for Grafana OnCall handles ticket events sent from New Relic webhooks.
The integration provides grouping, auto-acknowledge and auto-resolve logic via customizable alert templates.
> You must have the [role of Admin]({{< relref "user-and-team-management" >}}) to be able to create integrations in Grafana OnCall.
> You must have the [role of Admin][user-and-team-management] to be able to create integrations in Grafana OnCall.
## Configuring Grafana OnCall to Receive Alerts from New Relic
@ -34,3 +34,8 @@ The integration provides grouping, auto-acknowledge and auto-resolve logic via c
3. Create "Webhook" notification channel.
4. Set the following URL: **OnCall Integration URL**
5. Check "Payload type" is JSON.
{{% docs/reference %}}
[user-and-team-management]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/user-and-team-management"
[user-and-team-management]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/user-and-team-management"
{{% /docs/reference %}}

View file

@ -18,7 +18,7 @@ weight: 500
The Pingdom integration for Grafana OnCall handles ticket events sent from Pingdom webhooks.
The integration provides grouping, auto-acknowledge and auto-resolve logic via customizable alert templates.
> You must have the [role of Admin]({{< relref "user-and-team-management" >}}) to be able to create integrations in Grafana OnCall.
> You must have the [role of Admin][user-and-team-management] to be able to create integrations in Grafana OnCall.
## Configuring Grafana OnCall to Receive Alerts from Pingdom
@ -35,3 +35,8 @@ The integration provides grouping, auto-acknowledge and auto-resolve logic via c
4. Go to "Reports" -> "Uptime" -> "Edit Check".
5. Select `Grafana OnCall` integration in the bottom.
6. Click "Modify Check" to save.
{{% docs/reference %}}
[user-and-team-management]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/user-and-team-management"
[user-and-team-management]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/user-and-team-management"
{{% /docs/reference %}}

View file

@ -18,7 +18,7 @@ weight: 500
The PRTG integration for Grafana OnCall handles ticket events sent from PRTG webhooks.
The integration provides grouping, auto-acknowledge and auto-resolve logic via customizable alert templates.
> You must have the [role of Admin]({{< relref "user-and-team-management" >}}) to be able to create integrations in Grafana OnCall.
> You must have the [role of Admin][user-and-team-management] to be able to create integrations in Grafana OnCall.
## Configuring Grafana OnCall to Receive Alerts from PRTG
@ -111,3 +111,8 @@ Catch
}
```
{{% docs/reference %}}
[user-and-team-management]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/user-and-team-management"
[user-and-team-management]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/user-and-team-management"
{{% /docs/reference %}}

View file

@ -18,7 +18,7 @@ weight: 500
The Sentry integration for Grafana OnCall handles ticket events sent from Sentry webhooks.
The integration provides grouping, auto-acknowledge and auto-resolve logic via customizable alert templates.
> You must have the [role of Admin]({{< relref "user-and-team-management" >}}) to be able to create integrations in Grafana OnCall.
> You must have the [role of Admin][user-and-team-management] to be able to create integrations in Grafana OnCall.
## Configuring Grafana OnCall to Receive Alerts from Sentry
@ -54,3 +54,8 @@ level, event frequency, or specific tags.
8. Save the alert rule.
Once the alert conditions are met, Sentry will trigger the webhook action and send a request to the Grafana OnCall.
{{% docs/reference %}}
[user-and-team-management]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/user-and-team-management"
[user-and-team-management]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/user-and-team-management"
{{% /docs/reference %}}

View file

@ -0,0 +1,140 @@
---
aliases:
- servicenow/
- /docs/oncall/latest/integrations/available-integrations/configure-servicenow/
canonical: https://grafana.com/docs/oncall/latest/integrations/available-integrations/configure-servicenow/
keywords:
- Grafana Cloud
- Alerts
- Notifications
- on-call
- webhooks
- ServiceNow
title: ServiceNow
weight: 500
---
# Integrate Grafana OnCall with ServiceNow
Grafana OnCall can automatically create, assign and resolve incidents in ServiceNow via [outgoing webhooks]({{< relref "_index.md" >}}).
This guide provides example webhook configurations for common use cases, as well as information on how to set up a user in ServiceNow to be used by Grafana OnCall.
## Prerequisites
1. Create a new user in ServiceNow to be used by Grafana OnCall. Obtain the username and password for the user,
these credentials will be used to communicate with ServiceNow REST API.
2. Make sure the user has appropriate permissions to create and update incidents in ServiceNow. By default, the user will need to have the `sn_incident_write` role.
## Create incidents in ServiceNow
The steps below describe how to create an outgoing webhook in Grafana OnCall that will allow to automatically create
incidents in ServiceNow from Grafana OnCall alert groups.
Create a new Outgoing Webhook in Grafana OnCall, and configure it as follows:
- Trigger type: `Alert Group Created`
- Integrations: Select integrations that will trigger the webhook
- HTTP method: `POST`
- Webhook URL:
```text
https://<INSTANCE>.service-now.com/api/now/table/incident
```
Replace `<INSTANCE>` with your ServiceNow instance.
- Username: Username of the [ServiceNow user](#prerequisites)
- Password: Password of the [ServiceNow user](#prerequisites)
Use the following JSON template as webhook data:
```json
{
"short_description": "{{alert_group.title}}",
"description": "This incident is created automatically by Grafana OnCall.",
"work_notes": "Grafana OnCall alert group: [code]<a target='_blank' href='{{alert_group.permalinks.web}}'>{{alert_group.id}}</a>[/code]",
"category": "Software"
}
```
## Assign incidents in ServiceNow
The steps below describe how to create an outgoing webhook in Grafana OnCall that will allow to automatically assign incidents in ServiceNow.
The assignment will be performed when an alert group is acknowledged in Grafana OnCall.
- Trigger type: `Acknowledged`
- Integrations: Select integrations that will trigger the webhook
- HTTP method: `PUT`
- Webhook URL:
```text
https://<INSTANCE>.service-now.com/api/now/table/incident/{{responses.<WEBHOOK_ID>.result.sys_id}}
```
Replace `<INSTANCE>` with your ServiceNow instance, and `<WEBHOOK_ID>` with the ID of the [webhook used for creating incidents](#create-incidents-in-servicenow).
- Username: Username of the [ServiceNow user](#prerequisites)
- Password: Password of the [ServiceNow user](#prerequisites)
Use the following JSON template as webhook data:
```json
{
"assigned_to": "{{user.email}}"
}
```
>**Note**: The incident will be assigned to the user that acknowledged the alert group in Grafana OnCall.
The assignment will fail if the user email does not exist in ServiceNow.
## Resolve incidents in ServiceNow
The steps below describe how to create an outgoing webhook in Grafana OnCall that will allow to automatically close
incidents in ServiceNow when an alert group is resolved in Grafana OnCall.
- Trigger type: `Resolved`
- Integrations: Select integrations that will trigger the webhook
- HTTP method: `PUT`
- Webhook URL:
```text
https://<INSTANCE>.service-now.com/api/now/table/incident/{{responses.<WEBHOOK_ID>.result.sys_id}}
```
Replace `<INSTANCE>` with your ServiceNow instance, and `<WEBHOOK_ID>` with the ID of the [webhook used for creating incidents](#create-incidents-in-servicenow).
- Username: Username of the [ServiceNow user](#prerequisites)
- Password: Password of the [ServiceNow user](#prerequisites)
Use the following JSON template as webhook data:
```json
{
"state": 6,
"close_code": "Resolved by caller",
"close_notes": "Resolved by Grafana OnCall."
}
```
>**Note**: Values for fields `state` and `close_code` may be different for your ServiceNow instance, please check and update the values accordingly.
## Advanced usage
The examples above describe how to create outgoing webhooks in Grafana OnCall that will allow to automatically create, assign and resolve incidents in ServiceNow.
Consider modifying example templates to fit your use case (e.g. to include more information on alert groups).
Refer to [outgoing webhooks documentation]({{< relref "_index.md" >}}) for more information on available template variables and webhook configuration.
For more information on ServiceNow REST API, refer to [ServiceNow REST API documentation](https://developer.servicenow.com/dev.do#!/reference/api/sandiego/rest).

View file

@ -18,7 +18,7 @@ weight: 500
The Stackdriver integration for Grafana OnCall handles ticket events sent from Stackdriver webhooks.
The integration provides grouping, auto-acknowledge and auto-resolve logic via customizable alert templates.
> You must have the [role of Admin]({{< relref "user-and-team-management" >}}) to be able to create integrations in Grafana OnCall.
> You must have the [role of Admin][user-and-team-management] to be able to create integrations in Grafana OnCall.
## Configuring Grafana OnCall to Receive Alerts from Stackdriver
@ -32,3 +32,8 @@ The integration provides grouping, auto-acknowledge and auto-resolve logic via c
1. Create a notification channel in Stackdriver by navigating to Workspace Settings -> WEBHOOKS -> Add Webhook **OnCall Integration URL**
2. Create and alert in Stackdriver by navigating to Alerting -> Policies -> Add Policy -> Choose Notification Channel using the channel set up in step 1
{{% docs/reference %}}
[user-and-team-management]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/user-and-team-management"
[user-and-team-management]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/user-and-team-management"
{{% /docs/reference %}}

View file

@ -18,7 +18,7 @@ weight: 500
The UptimeRobot integration for Grafana OnCall handles ticket events sent from UptimeRobot webhooks.
The integration provides grouping, auto-acknowledge and auto-resolve logic via customizable alert templates.
> You must have the [role of Admin]({{< relref "user-and-team-management" >}}) to be able to create integrations in Grafana OnCall.
> You must have the [role of Admin][user-and-team-management] to be able to create integrations in Grafana OnCall.
## Configuring Grafana OnCall to Receive Alerts from UptimeRobot
@ -59,3 +59,8 @@ POST Value (JSON Format):
1. Set URL to <http://devnull.amixr.io> or any other non-existent domain
1. Click Checkbox next to Amixr Alert Contact (created in the previous step)
1. Click Create Monitor
{{% docs/reference %}}
[user-and-team-management]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/user-and-team-management"
[user-and-team-management]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/user-and-team-management"
{{% /docs/reference %}}

View file

@ -60,4 +60,9 @@ https://a-prod-us-central-0.grafana.net/integrations/v1/formatted_webhook/m12xmI
```
To learn how to use custom alert templates for formatted webhooks, see
[Configure alerts templates]({{< relref "jinja2-templating" >}}).
[Configure alerts templates][jinja2-templating].
{{% docs/reference %}}
[jinja2-templating]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/jinja2-templating"
[jinja2-templating]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/jinja2-templating"
{{% /docs/reference %}}

View file

@ -8,6 +8,7 @@ keywords:
- Alerts
- Notifications
- on-call
- webhooks
- Zendesk
title: Zendesk
weight: 500
@ -18,7 +19,7 @@ weight: 500
The Zendesk integration for Grafana OnCall handles ticket events sent from Zendesk webhooks.
The integration provides grouping, auto-acknowledge and auto-resolve logic via customizable alert templates.
> You must have the [role of Admin]({{< relref "user-and-team-management" >}}) to be able to create integrations in Grafana OnCall.
> You must have the [role of Admin][user-and-team-management] to be able to create integrations in Grafana OnCall.
## Configuring Grafana OnCall to Receive Alerts from Zendesk
@ -64,3 +65,105 @@ Grafana OnCall provides grouping, auto-acknowledge and auto-resolve logic for th
- Alert groups are auto-resolved when the ticket status is set to "Solved"
To customize this behaviour, consider modifying alert templates in integration settings.
## Configuring Grafana OnCall to send data to Zendesk
Grafana OnCall can automatically create and resolve tickets in Zendesk via [outgoing webhooks]({{< relref "_index.md" >}}).
This guide provides example webhook configurations for common use cases, as well as information on how to set up a user in Zendesk to be used by Grafana OnCall.
### Prerequisites
1. Create a new user in Zendesk to be used by Grafana OnCall.
[Obtain an API token for the user](https://support.zendesk.com/hc/en-us/articles/4408889192858-Generating-a-new-API-token),
these credentials will be used to communicate with Zendesk API.
2. Make sure the user has appropriate permissions to create and update tickets in Zendesk.
### Create tickets in Zendesk
The steps below describe how to create an outgoing webhook in Grafana OnCall that will allow to automatically create
tickets in Zendesk from Grafana OnCall alert groups.
Create a new Outgoing Webhook in Grafana OnCall, and configure it as follows:
- Trigger type: `Alert Group Created`
- Integrations: Select integrations that will trigger the webhook
- HTTP method: `POST`
- Webhook URL:
```text
https://<INSTANCE>.zendesk.com/api/v2/tickets
```
Replace `<INSTANCE>` with your Zendesk instance.
- Username: Username of the [Zendesk user](#prerequisites), followed by `/token` (e.g. `user@example.com/token`)
- Password: API token of the [Zendesk user](#prerequisites)
Use the following JSON template as webhook data:
```json
{
"ticket": {
"type": "incident",
"subject": "{{alert_group.title}}",
"comment": {
"body": "This ticket is created automatically by Grafana OnCall. Alert group {{alert_group.id}}: {{alert_group.permalinks.web}}"
}
}
}
```
### Resolve tickets in Zendesk
The steps below describe how to create an outgoing webhook in Grafana OnCall that will allow to automatically resolve
tickets in Zendesk when an alert group is resolved in Grafana OnCall.
- Trigger type: `Resolved`
- Integrations: Select integrations that will trigger the webhook
- HTTP method: `PUT`
- Webhook URL:
```text
https://<INSTANCE>.zendesk.com/api/v2/tickets/{{responses.<WEBHOOK_ID>.ticket.id}}
```
Replace `<INSTANCE>` with your Zendesk instance, and `<WEBHOOK_ID>` with the ID of the [webhook used for creating tickets](#create-tickets-in-zendesk).
- Username: Username of the [Zendesk user](#prerequisites), followed by `/token` (e.g. `user@example.com/token`)
- Password: API token of the [Zendesk user](#prerequisites)
Use the following JSON template as webhook data:
```json
{
"ticket": {
"status": "solved",
"comment": {
"body": "Resolved by Grafana OnCall.",
"public": false
}
}
}
```
### Advanced usage
The examples above describe how to create outgoing webhooks in Grafana OnCall that will allow to automatically create and resolve tickets in Zendesk.
Consider modifying example templates to fit your use case (e.g. to include more information on alert groups).
Refer to [outgoing webhooks documentation]({{< relref "_index.md" >}}) for more information on available template variables and webhook configuration.
For more information on Zendesk API, refer to [Zendesk API documentation](https://developer.zendesk.com/api-reference/ticketing/tickets/tickets/).
{{% docs/reference %}}
[user-and-team-management]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/user-and-team-management"
[user-and-team-management]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/user-and-team-management"
{{% /docs/reference %}}

View file

@ -18,7 +18,7 @@ weight: 800
# Notify people
Grafana OnCall directly supports the export of alert notifications to some popular messaging applications like Slack and
Telegram. You can use [outgoing webhooks]({{< relref "outgoing-webhooks" >}}) for applications that aren't directly
Telegram. You can use [outgoing webhooks][outgoing-webhooks] for applications that aren't directly
supported.
To configure supported messaging apps, see the following topics:
@ -49,3 +49,8 @@ To configure a users notification policy:
1. Click **Add notification step** and use the dropdowns to specify the notification method and frequency. Notification steps will be followed in the order they
are listed.
{{% docs/reference %}}
[outgoing-webhooks]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/outgoing-webhooks"
[outgoing-webhooks]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/outgoing-webhooks"
{{% /docs/reference %}}

View file

@ -17,7 +17,7 @@ weight: 100
# Phone Calls and SMS notifications
Grafana OnCall Cloud includes SMS and Phone notifications, OSS users [could leverage]({{< relref "open-source" >}}) Grafana Cloud as a relay or
Grafana OnCall Cloud includes SMS and Phone notifications, OSS users [could leverage][open-source] Grafana Cloud as a relay or
configure other providers like Twilio.
## Are there additional costs for outgoing calls/sms?
@ -41,4 +41,12 @@ In order to learn the phone number used by OnCall, make a test call at the "Phon
There are cases when OnCall is not able to make phone calls or send SMS to certain regions or specific phone numbers.
We're working hard to fix such cases, but kindly asking to test your personal notification chain to make sure OnCall
is able to notify you. Also we suggest to back up Phone Calls and SMS with other notification methods such as
[Mobile App]({{< relref "mobile-app" >}}).
[Mobile App][mobile-app].
{{% docs/reference %}}
[mobile-app]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/mobile-app"
[mobile-app]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/mobile-app"
[open-source]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/open-source"
[open-source]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/open-source/"
{{% /docs/reference %}}

View file

@ -29,7 +29,7 @@ To install the Slack integration, you must have Admin permissions in your Grafan
that youd like to integrate with.
For Open Source Grafana OnCall Slack installation guidance, refer to
[Open Source Grafana OnCall]({{< relref "open-source" >}}).
[Open Source Grafana OnCall][open-source].
## Install Slack integration for Grafana OnCall
@ -117,3 +117,8 @@ Use message shortcuts to add resolution notes directly from Slack. Message short
1. Hover over the message and select **More actions** from the menu options.
1. Select **Add as resolution note**.
1. The Grafana OnCall app will react to the message in Slack with the memo emoji and add the message to the alert group timeline.
{{% docs/reference %}}
[open-source]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/open-source"
[open-source]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/open-source"
{{% /docs/reference %}}

View file

@ -19,14 +19,14 @@ weight: 700
- Users with Viewer role cannot receive alert notifications, therefore, cannot be on-call.
For more information about permissions, refer to
[Manage users and teams for Grafana OnCall]({{< relref "user-and-team-management" >}})
[Manage users and teams for Grafana OnCall][user-and-team-management]
### Web-based schedule
Configure and manage on-call schedules directly in the Grafana OnCall plugin. Easily configure and preview rotations,
see teammates' time zones, and add overrides.
Learn more about [Web-based schedules]({{< relref "web-schedule" >}})
Learn more about [Web-based schedules][web-schedule]
### iCal import
@ -34,7 +34,7 @@ Use any calendar service that uses the iCal format to manage and customize on-ca
shifts from your calendar app to Grafana OnCall for widely accessible scheduling. iCal imports appear in Grafana
OnCall as read-only schedules but can be leveraged similarly to a web-based schedule.
Learn more about [iCal import schedules]({{< relref "ical-schedules" >}})
Learn more about [iCal import schedules][ical-schedules]
### Terraform
@ -44,3 +44,14 @@ read-only and cannot be edited from the UI.
To learn more, read our [Get started with Grafana OnCall and Terraform](
<https://grafana.com/blog/2022/08/29/get-started-with-grafana-oncall-and-terraform/>) blog post.
{{% docs/reference %}}
[ical-schedules]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/on-call-schedules/ical-schedules"
[ical-schedules]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/on-call-schedules/ical-schedules"
[user-and-team-management]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/user-and-team-management"
[user-and-team-management]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/user-and-team-management"
[web-schedule]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/on-call-schedules/web-schedule"
[web-schedule]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/on-call-schedules/web-schedule"
{{% /docs/reference %}}

View file

@ -18,4 +18,9 @@ teams in the org, we suggest considering storing schedules as code.
- [Get started with Grafana OnCall and Terraform (blogpost)](https://grafana.com/blog/2022/08/29/get-started-with-grafana-oncall-and-terraform/)
- [Grafana Terraform provider reference (OnCall resources are managed using this provider)](https://registry.terraform.io/providers/grafana/grafana/latest/docs/resources/oncall_schedule)
- [OnCall API]({{< relref "oncall-api-reference" >}})
- [OnCall API][oncall-api-reference]
{{% docs/reference %}}
[oncall-api-reference]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/oncall-api-reference"
[oncall-api-reference]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/oncall-api-reference"
{{% /docs/reference %}}

View file

@ -20,7 +20,7 @@ OnCall as read-only schedules but can be leveraged similarly to a web-based sche
> Unfortunately there is a known limitation with Google Calendar import and export.
> Google may take up to 24h to import OnCall's calendar (OnCall -> Google) and sometimes our customers report delay in
> exporting (Google Calendar -> OnCall). If actual calendar is critical for you, we suggest checking
> [web-based scheduling]({{< relref "web-schedule" >}}).
> [web-based scheduling]
## Before you begin
@ -99,3 +99,8 @@ contain a level marker result in all overlapping users receiving notifications.
For example, users AliceGrafana and BobGrafana have overlapping schedules but BobGrafana is the intended primary
contact. The calendar events titles would be `[L1] BobGrafana` and `[L0] AliceGrafana` - In this case AliceGrafana
maintains the default [L0] status, and would not receive notifications during the overlapping time with BobGrafana.
{{% docs/reference %}}
[web-schedule]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/on-call-schedules/web-schedule"
[web-schedule]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/on-call-schedules/web-schedule"
{{% /docs/reference %}}

View file

@ -74,7 +74,7 @@ The above command returns JSON structured in the following way:
Integrations are sources of alerts and alert groups for Grafana OnCall.
For example, to learn how to integrate Grafana OnCall with Alertmanager see
[Alertmanager]({{< relref "../integrations/alertmanager" >}}).
[Alertmanager][alertmanager].
**HTTP request**
@ -314,3 +314,8 @@ curl "{{API_URL}}/api/v1/integrations/CFRPV98RPR1U8/" \
**HTTP request**
`DELETE {{API_URL}}/api/v1/integrations/<INTEGRATION_ID>/`
{{% docs/reference %}}
[alertmanager]: "/docs/oncall/ -> /docs/oncall/<ONCALL VERSION>/integrations/alertmanager"
[alertmanager]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/integrations/alertmanager"
{{% /docs/reference %}}

View file

@ -1,6 +1,7 @@
---
aliases:
- ../outgoing-webhooks/
- ../integrations/configure-outgoing-webhooks/
- /docs/oncall/latest/outgoing-webhooks/
canonical: https://grafana.com/docs/oncall/latest/outgoing-webhooks/
keywords:
- Grafana Cloud
@ -9,54 +10,478 @@ keywords:
- on-call
- amixr
- webhooks
title: Outgoing Webhooks
weight: 900
title: Configure outgoing webhooks for Grafana OnCall
weight: 500
---
# Configure outgoing webhooks for Grafana OnCall
Outgoing webhooks allow you to send alert details to a specified URL from Grafana OnCall. Once an outgoing webhook is
configured, you can use it as a notification method in escalation chains.
Outgoing webhooks are used by Grafana OnCall to send data to a URL in a flexible way. These webhooks can be
triggered from a variety of event types and make use of Jinja2 to transform data into the format required at
the destination URL. Each outgoing webhook receives contextual data when executed which can be processed by
Jinja2 templates to customize the request being sent.
To automatically send alert data to a destination URL via outgoing webhook:
## Creating an outgoing webhook
1. In Grafana OnCall, navigate to **Outgoing Webhooks** and click **+ Create**.
This is also the place to edit and delete existing outgoing webhooks.
2. Provide a name for your outgoing webhook and enter the destination URL.
3. If the destination requires authentication, enter your credentials.
You can enter a username and password (HTTP) or an authorization header formatted in JSON.
4. Configure the webhook payload in the **Data** field.
5. Click **Create Webhook**.
To create an outgoing webhook navigate to **Outgoing Webhooks** and click **+ Create**. On this screen outgoing
webhooks can be viewed, edited and deleted. To create the outgoing webhook populate the required fields and
click **Create Webhook**
The format you use to call the variables must match the structure of how the fields are nested in the alert payload.
The **Data** field can use the following four variables to auto-populate the webhook payload with information about
the first alert in the alert group:
### Outgoing webhook fields
- `{{ alert_payload }}`
- `{{ alert_group_id }}`
The outgoing webhook is defined by the following fields. For more information about template usage
see [Outgoing webhook templates)](#outgoing-webhook-templates) section.
`alert_payload` is always the first level of any variable you want to call.
#### ID
The following is an example of an entry in the **Data** field that would return an alert name and description.
This field is generated after an outgoing webhook has been created. It is used to reference the responses of
other webhooks, see [Advanced Usage - Using response data](#using-response-data) for more details.
{
"name": "{{ alert_payload.labels.alertname }}",
"message": "{{ alert_payload.annotations.description }}"
#### Name
Display name of the outgoing webhook.
| Required | [Template Accepted](#outgoing-webhook-templates) | Default Value |
|:--------:|:------------------------------------------------:|:-------------:|
| ✔️ | ❌ | _Empty_ |
#### Enabled
Controls whether the outgoing webhook will trigger or is ignored.
| Required | [Template Accepted](#outgoing-webhook-templates) | Default Value |
|:--------:|:------------------------------------------------:|:-------------:|
| ✔️ | ❌ | _True_ |
#### Assign to Team
Sets which team owns the outgoing webhook for filtering and visibility.
This setting does not restrict outgoing webhook execution to events from the selected team.
| Required | [Template Accepted](#outgoing-webhook-templates) | Default Value |
|:--------:|:------------------------------------------------:|:-------------:|
| ❌ | ❌ | _Empty_ |
#### Trigger Type
The type of event that will cause this outgoing webhook to execute. The types of triggers are:
- [Escalation Step](#escalation-step)
- [Alert Group Created](#alert-group-created)
- [Acknowledged](#acknowledged)
- [Resolved](#resolved)
- [Silenced](#silenced)
- [Unsilenced](#unsilenced)
- [Unresolved](#unresolved)
- [Unacknowledged](#acknowledged)
For more details about types of triggers see [Event types](#event-types)
| Required | [Template Accepted](#outgoing-webhook-templates) | Default Value |
|:--------:|:------------------------------------------------:|:-------------:|
| ✔️ | ❌ | _None_ |
#### HTTP Method
The HTTP method used in the request made by the outgoing webhook. This should match what is required by the URL
you are sending to.
| Required | [Template Accepted](#outgoing-webhook-templates) | Default Value |
|:--------:|:------------------------------------------------:|:-------------:|
| ✔️ | ❌ | _POST_ |
#### Integrations
Restricts the outgoing webhook to only trigger if the event came from a selected integration.
If no integrations are selected the outgoing webhook will trigger for any integration.
| Required | [Template Accepted](#outgoing-webhook-templates) | Default Value |
|:--------:|:------------------------------------------------:|:-------------:|
| ❌ | ❌ | _None_ |
#### Webhook URL
The destination URL the outgoing webhook will make a request to. This must be a FQDN.
| Required | [Template Accepted](#outgoing-webhook-templates) | Default Value |
|:--------:|:------------------------------------------------:|:-------------:|
| ✔️ | ✔️ | _Empty_ |
#### Webhook Headers
Headers to add to the outgoing webhook request.
| Required | [Template Accepted](#outgoing-webhook-templates) | Default Value |
|:--------:|:------------------------------------------------:|:-------------:|
| ❌ | ✔️ | _Empty_ |
#### Username
Username to use when making the outgoing webhook request.
| Required | [Template Accepted](#outgoing-webhook-templates) | Default Value |
|:--------:|:------------------------------------------------:|:-------------:|
| ❌ | ❌ | _Empty_ |
#### Password
Password to use when making the outgoing webhook request.
| Required | [Template Accepted](#outgoing-webhook-templates) | Default Value |
|:--------:|:------------------------------------------------:|:-------------:|
| ❌ | ❌ | _Empty_ |
#### Authorization Header
Authorization header to use when making the outgoing webhook request.
| Required | [Template Accepted](#outgoing-webhook-templates) | Default Value |
|:--------:|:------------------------------------------------:|:-------------:|
| ❌ | ❌ | _None_ |
#### Trigger Template
A template used to dynamically determine whether the webhook should execute based on the content of the payload.
If the template evaluates to Empty, True or 1 the webhook will execute.
| Required | [Template Accepted](#outgoing-webhook-templates) | Default Value |
|:--------:|:------------------------------------------------:|:-------------:|
| ❌ | ✔️ | _Empty_ |
#### Data
The main body of the request to be sent by the outgoing webhook.
| Required | [Template Accepted](#outgoing-webhook-templates) | Default Value |
|:--------:|:------------------------------------------------:|:-------------:|
| ❌ | ✔️ | _Empty_ |
#### Forward All
Toggle to send the entire webhook payload instead of using the values in the **Data** field
| Required | [Template Accepted](#outgoing-webhook-templates) | Default Value |
|:--------:|:------------------------------------------------:|:-------------:|
| ❌ | ❌ | _False_ |
## Outgoing webhook templates
The fields that accept a Jinja2 template in outgoing webhooks are able to process data to customize the output.
The following is an example of the data available to access from a template. Some data depending on the timing
of the webhook and the triggering event may not always be available,
see [field descriptions](#outgoing-webhook-data-fields) specific details. The format you use to call the variables
must match the structure of how the fields are nested in the data.
```json
{
"event": {
"type": "resolve",
"time": "2023-04-19T21:59:21.714058+00:00"
},
"user": {
"id": "UVMX6YI9VY9PV",
"username": "admin",
"email": "admin@localhost"
},
"alert_group": {
"id": "I6HNZGUFG4K11",
"integration_id": "CZ7URAT4V3QF2",
"route_id": "RKHXJKVZYYVST",
"alerts_count": 1,
"state": "resolved",
"created_at": "2023-04-19T21:53:48.231148Z",
"resolved_at": "2023-04-19T21:59:21.714058Z",
"acknowledged_at": "2023-04-19T21:54:39.029347Z",
"title": "Incident",
"permalinks": {
"slack": null,
"telegram": null,
"web": "https://**********.grafana.net/a/grafana-oncall-app/alert-groups/I6HNZGUFG4K11"
}
The following is an example would return an alert name and the alert's labels.
{
"alertname" : "{{ alert_payload.labels.alertname }}",
"labels" : "{{ alert_payload.labels }}"
},
"alert_group_id": "I6HNZGUFG4K11",
"alert_payload": {
"endsAt": "0001-01-01T00:00:00Z",
"labels": {
"region": "eu-1",
"alertname": "TestAlert"
},
"status": "firing",
"startsAt": "2018-12-25T15:47:47.377363608Z",
"amixr_demo": true,
"annotations": {
"description": "This alert was sent by user for the demonstration purposes"
},
"generatorURL": ""
},
"integration": {
"id": "CZ7URAT4V3QF2",
"type": "webhook",
"name": "Main Integration - Webhook",
"team": "Webhooks Demo"
},
"notified_users": [],
"users_to_be_notified": [],
"responses": {
"WHP936BM1GPVHQ": {
"id": "7Qw7TbPmzppRnhLvK3AdkQ",
"created_at": "15:53:50",
"status": "new",
"content": {
"message": "Ticket created!",
"region": "eu"
}
}
}
}
```
By default, this will return labels in a list format. If you'd like your labels to be sent in formatted JSON, please use `| tojson()` in your data. For example:
### Outgoing webhook data fields
{
"alertname" : "{{ alert_payload.labels.alertname }}",
"labels" : "{{ alert_payload.labels | tojson() }}"
}
#### `event`
> **NOTE:** If you receive an error message and cannot create an outgoing webhook, verify that your JSON is
> formatted correctly.
Context information about the event that triggered the outgoing webhook.
- `{{ event.type }}` - Lower case string matching [type of event](#event-types)
- `{{ event.time }}` - Time event was triggered
#### `user`
Information about the user if the source of the event was a user. If a user acknowledges an alert group after
receiving a notification this field will have that user's information. If an alert group was auto-resolved based
on criteria in the integration this field will be empty.
- `{{ user.id }}` - [UID](#uid) of the user within Grafana OnCall
- `{{ user.username }}` - Username in Grafana
- `{{ user.email }}` - Email associated with user's Grafana account
#### `alert_group`
Details about the alert group associated with this event.
- `{{ alert_group.id }}` - [UID](#uid) of alert group
- `{{ alert_group.integration_id }}` - [UID](#uid) of integration that alert came through
- `{{ alert_group.route_id }}` - [UID](#uid) of route of integration that alert came through
- `{{ alert_group.alerts_count }}` - Count of alerts in alert group
- `{{ alert_group.state }}` - Current state of alert group
- `{{ alert_group.created_at }}` - Timestamp alert group was created
- `{{ alert_group.resolved_at }}` - Timestamp alert group was resolved (None if not resolved yet)
- `{{ alert_group.acknowledged_at }}` - Timestamp alert group was acknowledged (None if not acknowledged yet)
- `{{ alert_group.title }}` - Title of alert group
- `{{ alert_group.permalinks }}` - Links to alert group in web and chat ops if available
#### `{{ alert_group_id }}`
UID of alert group, same as `{{ alert_group.id }}` (For convenience and compatibility with earler versions of Grafana OnCall)
#### `alert_payload`
Content of the first alert in the alert group. Content will depend on what the alert source has sent.
Some commonly used fields are:
- `{{ alert_payload.labels.alertname }}`
- `{{ alert_payload.annotations.description }}`
#### `integration`
Details about the integration that received this alert
- `{{ integration.id }}` - [UID](#uid) of integration
- `{{ integration.type }}` - Type of integration (grafana, alertmanager, webhook, etc.)
- `{{ integration.name }}` - Name of integration
- `{{ integration.team }}` - Team integration belongs to if integration is assigned to a team
#### `notified_users`
Array of users that have received notifications about the associated alert group. Each user element in the array
consists of `id`,`username`,`email`. Depending on timing of events and notifications this might not be populated yet
if notifications are still in progress. Access as `{{ notified_users[0].username }}` for example.
#### `users_to_notify`
Array of users that could potentially be notified based on the configured escalation chain. Each user element in the array
consists of `id`,`username`,`email`. Array elements are ordered based on the order users will be notified with the
first element being the user that will be notified next. Like `notified_users` depending on timing of notifications
a user in this array may have already been notified by the time this data is being processed. Access as
`{{ users_to_notify[0].username }}` for example.
#### `responses`
The responses field is used to access the response data of other webhooks that are associated with this alert group.
The keys inside responses are the [UID](#uid) of other outgoing webhooks. The values inside each response is the latest
response of the referenced webhook when it was executed on behalf of the current alert group.
See [Advanced Usage - Using response data](#using-response-data) for more details. Access as
`{{ responses["WHP936BM1GPVHQ"].content.message }}` for example
### UID
Templates often use UIDs to make decisions about what actions to take if you need to find the UID of an object
in the user interface to reference they can be found in the following places:
- Outgoing Webhook - In the table there is an info icon, UID displayed on hover, click to copy to clipboard
- Integration - In integrations beside the name is an info icon, UID displayed on hover, click to copy to clipboard
- Routes - With an integration selected beside Send Demo Alert is an infor icon, UID displayed on hover,
click to copy to clipboard
- Alert group - When viewing an alert group UID is visible in the browser URL
- User - When viewing a user's profile UID is visible in the browser URL
UIDs are also visible in the browser URL when a specific object is selected for view or edit.
### Template examples
The following is an example of an entry in the Data field that would return an alert name and description.
```json
{
"name": "{{ alert_payload.labels.alertname }}",
"message": "{{ alert_payload.annotations.description }}"
}
```
Here is an example using the user's email address as part of a URL:
```bash
https://someticketsystem.com/new-ticket?assign-user={{ user.email }}
```
#### Note about JSON
Take this template for example:
```json
{
"labels" : "{{ alert_payload.labels }}"
}
```
It will result in the following (Invalid JSON due to single quotes):
```json
{
"labels": {'region': 'eu-1', 'alertname': 'TestAlert'}
}
```
To fix change the template to:
```json
{
"labels" : "{{ alert_payload.labels | tojson()}}"
}
```
Now the result is correct:
```json
{
"labels": {
"alertname": "TestAlert",
"region": "eu-1"
}
}
```
## Event types
### Escalation Step
`event.type` `escalation`
This event will trigger when the outgoing webhook is included as a step in an escalation chain.
### Alert Group Created
`event.type` `alert group created`
This event will trigger when a new alert group is created.
### Acknowledged
`event.type` `acknowledge`
This event will trigger when a user acknowledges an alert group or an alert group is auto-acknowledged
by the integration.
### Resolved
`event.type` `resolve`
This event will trigger when a user resolves an alert group or an alert group is auto-resolved
by the integration.
### Silenced
`event.type` `silence`
This event will trigger when a user silences an alert group.
### Unsilenced
`event.type` `unsilence`
This event will trigger when a user unsilences an alert group or a silence expires.
### Unresolved
`event.type` `unresolve`
This event will trigger when a user unresolves an alert group.
### Unacknowledged
`event.type` `unacknowledge`
This event will trigger when a user unacknowledges an alert group.
## Viewing status of outgoing webhooks
In the outgoing webhooks table if a webhook is enabled **Last Run** will have the following information:
- Timestamp outgoing webhook was triggered
- HTTP response code
If more information is required you can click **Status** in the table. The status drawer shows the following:
- Webhook Name
- Webhook UID
- Trigger Type
- Last Run Time
- URL
- Response Code
- Response Body
- Trigger Template
- Request Headers
- Request Data
In the status drawer if a field makes use of a template it will display both the template and the result
otherwise it will only display the value. Fields which are not used are not shown.
## Advanced usage
### Using trigger template field
The [trigger template field](#trigger-type) can be used to provide control over whether a webhook will execute.
This is useful in situations where many different kinds of alerts are going to the same integration but only some of
them should call the webhook. To accomplish this the trigger template field can contain a template that will process
data from the alert group and evaluate to empty, True or 1 if the webhook should execute, any other values will result
in the webhook not executing.
### Using response data
The `responses` section of the payload makes available the responses of other webhooks that have acted on the same
alert group. To access them `responses` uses the `id` of the webhook as a key. The `id` can be found by hovering
over the info icon, clicking will copy the `id` to the clipboard. The response data of the most recent
execution of the webhook for this same alert group can be accessed this way.
The typical application of this is where a webhook will create a ticket in another system and OnCall needs to use
the `id` of that ticket to keep its status synchronized with the state changes being made in OnCall.
### Advanced examples
Integrate with third-party services:
- [JIRA]({{< relref "../integrations/jira" >}})
- [ServiceNow]({{< relref "../integrations/servicenow" >}})
- [Zendesk]({{< relref "../integrations/zendesk" >}})
{{< section >}}

View file

@ -1,2 +1,5 @@
# List of projects to provide to the make-docs script.
PROJECTS = oncall
PROJECTS := oncall
# Use alternative image until make-docs 3.0.0 is rolled out.
export DOCS_IMAGE := grafana/docs-base:dbd975af06

View file

@ -1,6 +1,7 @@
from unittest.mock import patch
import pytest
from django.conf import settings
from django.db.models import Max
from django.urls import reverse
from django.utils.timezone import timedelta
@ -913,8 +914,9 @@ def test_escalation_policy_escalation_options_webhooks(
url = reverse("api-internal:escalation_policy-escalation-options")
with patch("apps.api.views.escalation_policy.is_webhooks_enabled_for_organization", return_value=enabled):
response = client.get(url, format="json", **make_user_auth_headers(user, token))
settings.FEATURE_WEBHOOKS_2_ENABLED = enabled
response = client.get(url, format="json", **make_user_auth_headers(user, token))
returned_options = [option["value"] for option in response.json()]
if enabled:

View file

@ -14,7 +14,6 @@ from apps.api.serializers.escalation_policy import (
EscalationPolicyUpdateSerializer,
)
from apps.auth_token.auth import PluginAuthentication
from apps.webhooks.utils import is_webhooks_enabled_for_organization
from common.api_helpers.mixins import (
CreateSerializerMixin,
PublicPrimaryKeyMixin,
@ -132,10 +131,12 @@ class EscalationPolicyView(
def escalation_options(self, request):
choices = []
for step in EscalationPolicy.INTERNAL_API_STEPS:
if step == EscalationPolicy.STEP_TRIGGER_CUSTOM_WEBHOOK and not is_webhooks_enabled_for_organization(
self.request.auth.organization.pk
):
if step == EscalationPolicy.STEP_TRIGGER_CUSTOM_WEBHOOK and not settings.FEATURE_WEBHOOKS_2_ENABLED:
continue
if step == EscalationPolicy.STEP_TRIGGER_CUSTOM_BUTTON and settings.FEATURE_WEBHOOKS_2_ENABLED:
continue
verbal = EscalationPolicy.INTERNAL_API_STEPS_TO_VERBAL_MAP[step]
can_change_importance = (
step in EscalationPolicy.IMPORTANT_STEPS_SET or step in EscalationPolicy.DEFAULT_STEPS_SET

View file

@ -5,7 +5,6 @@ from rest_framework.views import APIView
from apps.auth_token.auth import PluginAuthentication
from apps.base.utils import live_settings
from apps.webhooks.utils import is_webhooks_enabled_for_organization
FEATURE_SLACK = "slack"
FEATURE_TELEGRAM = "telegram"
@ -60,7 +59,7 @@ class FeaturesAPIView(APIView):
if request.auth.organization.pk in enabled_web_schedules_orgs.json_value["org_ids"]:
enabled_features.append(FEATURE_WEB_SCHEDULES)
if is_webhooks_enabled_for_organization(request.auth.organization.pk):
if settings.FEATURE_WEBHOOKS_2_ENABLED:
enabled_features.append(FEATURE_WEBHOOKS2)
return enabled_features

View file

@ -1,5 +1,6 @@
import json
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
from django_filters import rest_framework as filters
from rest_framework import status
@ -14,7 +15,7 @@ from apps.api.permissions import RBACPermission
from apps.api.serializers.webhook import WebhookResponseSerializer, WebhookSerializer
from apps.auth_token.auth import PluginAuthentication
from apps.webhooks.models import Webhook, WebhookResponse
from apps.webhooks.utils import apply_jinja_template_for_json, is_webhooks_enabled_for_organization
from apps.webhooks.utils import apply_jinja_template_for_json
from common.api_helpers.exceptions import BadRequest
from common.api_helpers.filters import ByTeamModelFieldFilterMixin, ModelFieldFilterMixin, TeamModelMultipleChoiceFilter
from common.api_helpers.mixins import PublicPrimaryKeyMixin, TeamFilteringMixin
@ -103,8 +104,8 @@ class WebhooksView(TeamFilteringMixin, PublicPrimaryKeyMixin, ModelViewSet):
instance.delete()
def check_webhooks_2_enabled(self):
if not is_webhooks_enabled_for_organization(self.request.auth.organization.pk):
raise PermissionDenied("Webhooks 2 not enabled for organization. Permission denied.")
if not settings.FEATURE_WEBHOOKS_2_ENABLED:
raise PermissionDenied("Webhooks 2 not enabled. Permission denied.")
@action(methods=["get"], detail=False)
def filters(self, request):

View file

@ -0,0 +1,77 @@
# Generated by Django 3.2.19 on 2023-07-12 16:13
import logging
from django.core.exceptions import ObjectDoesNotExist
from django.db import migrations
from apps.alerts.models import EscalationPolicy
from apps.webhooks.models import Webhook
LEGACY_SUFFIX = " (Legacy)"
logger = logging.getLogger(__name__)
def convert_custom_button_to_webhook(apps, schema_editor):
CustomButton = apps.get_model("alerts", "CustomButton")
Webhooks = apps.get_model("webhooks", "Webhook")
EscalationPolicies = apps.get_model("alerts", "EscalationPolicy")
for cb in CustomButton.objects.all():
webhook, _ = Webhooks.objects.get_or_create(
organization=cb.organization,
team=cb.team,
name=cb.name + LEGACY_SUFFIX,
is_legacy=True,
defaults=dict(
created_at=cb.created_at,
url=cb.webhook,
username=cb.user,
password=cb.password,
authorization_header=cb.authorization_header,
trigger_type=Webhook.TRIGGER_ESCALATION_STEP,
forward_all=cb.forward_whole_payload,
data=cb.data,
)
)
# migrate related escalation policies
EscalationPolicies.objects.filter(
step=EscalationPolicy.STEP_TRIGGER_CUSTOM_BUTTON,
custom_button_trigger=cb,
).update(
step=EscalationPolicy.STEP_TRIGGER_CUSTOM_WEBHOOK,
custom_webhook=webhook,
)
def undo_custom_button_to_webhook(apps, schema_editor):
CustomButton = apps.get_model("alerts", "CustomButton")
Webhooks = apps.get_model("webhooks", "Webhook")
EscalationPolicies = apps.get_model("alerts", "EscalationPolicy")
for webhook in Webhooks.objects.filter(is_legacy=True):
try:
cb = CustomButton.objects.get(name=webhook.name.removesuffix(LEGACY_SUFFIX), team=webhook.team, organization=webhook.organization)
except ObjectDoesNotExist:
logger.warning(f"Did not find matching custom button to revert {webhook.name} {webhook.organization.stack_slug}, skipping")
continue
EscalationPolicies.objects.filter(
step=EscalationPolicy.STEP_TRIGGER_CUSTOM_WEBHOOK,
custom_webhook=webhook,
).update(
step=EscalationPolicy.STEP_TRIGGER_CUSTOM_BUTTON,
custom_button_trigger=cb,
custom_webhook=None,
)
webhook.delete()
class Migration(migrations.Migration):
dependencies = [
('webhooks', '0007_webhookresponse_event_data'),
]
operations = [
migrations.RunPython(convert_custom_button_to_webhook, undo_custom_button_to_webhook)
]

View file

@ -4,7 +4,6 @@ import re
import socket
from urllib.parse import urlparse
from django.apps import apps
from django.conf import settings
from apps.base.utils import live_settings
@ -179,16 +178,3 @@ def serialize_event(event, alert_group, user, responses=None):
data["responses"] = responses
return data
def is_webhooks_enabled_for_organization(organization_id):
DynamicSetting = apps.get_model("base", "DynamicSetting")
enabled_webhooks_orgs = DynamicSetting.objects.get_or_create(
name="enabled_webhooks_2_orgs",
defaults={
"json_value": {
"org_ids": [],
}
},
)[0]
return organization_id in enabled_webhooks_orgs.json_value["org_ids"]

View file

@ -64,6 +64,7 @@ FEATURE_WEB_SCHEDULES_ENABLED = getenv_boolean("FEATURE_WEB_SCHEDULES_ENABLED",
FEATURE_MULTIREGION_ENABLED = getenv_boolean("FEATURE_MULTIREGION_ENABLED", default=False)
FEATURE_INBOUND_EMAIL_ENABLED = getenv_boolean("FEATURE_INBOUND_EMAIL_ENABLED", default=False)
FEATURE_PROMETHEUS_EXPORTER_ENABLED = getenv_boolean("FEATURE_PROMETHEUS_EXPORTER_ENABLED", default=False)
FEATURE_WEBHOOKS_2_ENABLED = getenv_boolean("FEATURE_WEBHOOKS_2_ENABLED", default=True)
GRAFANA_CLOUD_ONCALL_HEARTBEAT_ENABLED = getenv_boolean("GRAFANA_CLOUD_ONCALL_HEARTBEAT_ENABLED", default=True)
GRAFANA_CLOUD_NOTIFICATIONS_ENABLED = getenv_boolean("GRAFANA_CLOUD_NOTIFICATIONS_ENABLED", default=True)

View file

@ -21,6 +21,7 @@ interface GFormProps {
onSubmit: (data: any) => void;
onFieldRender?: (
formItem: FormItem,
disabled: boolean,
renderedControl: React.ReactElement,
values: any,
setValue: (value: string) => void
@ -31,9 +32,16 @@ const nullNormalizer = (value: string) => {
return value || null;
};
function renderFormControl(formItem: FormItem, register: any, control: any, onChangeFn: (field, value) => void) {
function renderFormControl(
formItem: FormItem,
register: any,
control: any,
disabled,
onChangeFn: (field, value) => void
) {
switch (formItem.type) {
case FormItemType.Input:
console.log({ ...register(formItem.name, formItem.validation) });
return (
<Input {...register(formItem.name, formItem.validation)} onChange={(value) => onChangeFn(undefined, value)} />
);
@ -131,7 +139,7 @@ function renderFormControl(formItem: FormItem, register: any, control: any, onCh
showLineNumbers={false}
monacoOptions={{
...MONACO_READONLY_CONFIG,
readOnly: formItem.isReadOnly,
readOnly: disabled,
}}
onChange={(value) => onChangeFn(field, value)}
/>
@ -160,8 +168,13 @@ class GForm extends React.Component<GFormProps, {}> {
setValue(formItem.name, undefined); // clear input value on hide
return null;
}
const disabled = formItem.disabled
? true
: formItem.getDisabled
? formItem.getDisabled(getValues())
: false;
const formControl = renderFormControl(formItem, register, control, (field, value) => {
const formControl = renderFormControl(formItem, register, control, disabled, (field, value) => {
field?.onChange(value);
this.forceUpdate();
});
@ -169,14 +182,16 @@ class GForm extends React.Component<GFormProps, {}> {
return (
<Field
key={formIndex}
disabled={formItem.getDisabled ? formItem.getDisabled(getValues()) : false}
disabled={disabled}
label={formItem.label || capitalCase(formItem.name)}
invalid={!!errors[formItem.name]}
error={formItem.label ? `${formItem.label} is required` : `${capitalCase(formItem.name)} is required`}
description={formItem.description}
>
{onFieldRender
? onFieldRender(formItem, formControl, getValues(), (value) => setValue(formItem.name, value))
? onFieldRender(formItem, disabled, formControl, getValues(), (value) =>
setValue(formItem.name, value)
)
: formControl}
</Field>
);

View file

@ -14,7 +14,7 @@ export interface FormItem {
name: string;
label?: string;
type: FormItemType;
isReadOnly?: boolean;
disabled?: boolean;
description?: string;
normalize?: (value: any) => any;
isVisible?: (data: any) => any;

View file

@ -442,6 +442,10 @@ export class EscalationPolicy extends React.Component<EscalationPolicyProps, any
);
}}
width={'auto'}
filterOptions={(id) => {
const webhook = outgoingWebhook2Store.items[id];
return webhook.trigger_type_name === 'Escalation step';
}}
/>
</WithPermissionControlTooltip>
);

View file

@ -152,7 +152,6 @@ export const form: { name: string; fields: FormItem[] } = {
label: 'Webhook Headers',
description: 'Request headers should be in JSON format.',
type: FormItemType.Monaco,
isReadOnly: true,
extra: {
rows: 3,
},
@ -174,7 +173,6 @@ export const form: { name: string; fields: FormItem[] } = {
{
name: 'trigger_template',
type: FormItemType.Monaco,
isReadOnly: true,
description:
'Trigger template is used to conditionally execute the webhook based on incoming data. The trigger template must be empty or evaluate to true or 1 for the webhook to be sent',
extra: {
@ -191,7 +189,6 @@ export const form: { name: string; fields: FormItem[] } = {
name: 'data',
getDisabled: (data) => Boolean(data?.forward_all),
type: FormItemType.Monaco,
isReadOnly: true,
description:
'Available variables: {{ event }}, {{ user }}, {{ alert_group }}, {{ alert_group_id }}, {{ alert_payload }}, {{ integration }}, {{ notified_users }}, {{ users_to_be_notified }}, {{ responses }}',
extra: {},

View file

@ -68,12 +68,19 @@ const OutgoingWebhook2Form = observer((props: OutgoingWebhook2FormProps) => {
};
};
const enrchField = (formItem: FormItem, renderedControl: React.ReactElement, values, setFormFieldValue) => {
const enrchField = (
formItem: FormItem,
disabled: boolean,
renderedControl: React.ReactElement,
values,
setFormFieldValue
) => {
if (formItem.type === FormItemType.Monaco) {
return (
<div className={cx('form-row')}>
<div className={cx('form-field')}>{renderedControl}</div>
<Button
disabled={disabled}
icon="edit"
variant="secondary"
onClick={getTemplateEditClickHandler(formItem, values, setFormFieldValue)}
@ -149,7 +156,7 @@ const OutgoingWebhook2Form = observer((props: OutgoingWebhook2FormProps) => {
key={WebhookTabs.Settings.key}
onChangeTab={() => {
setActiveTab(WebhookTabs.Settings.key);
history.push(`${PLUGIN_ROOT}/outgoing_webhooks_2/edit/${id}`);
history.push(`${PLUGIN_ROOT}/outgoing_webhooks/edit/${id}`);
}}
active={activeTab === WebhookTabs.Settings.key}
label={WebhookTabs.Settings.value}
@ -159,7 +166,7 @@ const OutgoingWebhook2Form = observer((props: OutgoingWebhook2FormProps) => {
key={WebhookTabs.LastRun.key}
onChangeTab={() => {
setActiveTab(WebhookTabs.LastRun.key);
history.push(`${PLUGIN_ROOT}/outgoing_webhooks_2/last_run/${id}`);
history.push(`${PLUGIN_ROOT}/outgoing_webhooks/last_run/${id}`);
}}
active={activeTab === WebhookTabs.LastRun.key}
label={WebhookTabs.LastRun.value}
@ -290,7 +297,7 @@ const WebhookTabsContent: React.FC<WebhookTabsProps> = ({
</div>
{data.is_legacy ? (
<div className={cx('content')}>
<Text type="secondary">Legacy migrated webhooks are not editable.</Text>
<Text type="secondary">Legacy migrated webhooks are not editable. Make a copy to make changes.</Text>
</div>
) : (
''

View file

@ -1,10 +1,11 @@
import React, { useEffect, useState } from 'react';
import React, { useCallback, useEffect, useState } from 'react';
import { Button, Drawer, HorizontalGroup, VerticalGroup } from '@grafana/ui';
import cn from 'classnames/bind';
import { debounce } from 'lodash-es';
import CheatSheet from 'components/CheatSheet/CheatSheet';
import { genericTemplateCheatSheet } from 'components/CheatSheet/CheatSheet.config';
import MonacoEditor from 'components/MonacoEditor/MonacoEditor';
import Text from 'components/Text/Text';
import styles from 'containers/IntegrationTemplate/IntegrationTemplate.module.scss';
@ -32,7 +33,7 @@ interface WebhooksTemplateEditorProps {
}
const WebhooksTemplateEditor: React.FC<WebhooksTemplateEditorProps> = ({ template, id, onHide, handleSubmit }) => {
const [isCheatSheetVisible] = useState(false);
const [isCheatSheetVisible, setIsCheatSheetVisible] = useState<boolean>(false);
const [changedTemplateBody, setChangedTemplateBody] = useState<string>(template.value);
const [editorHeight, setEditorHeight] = useState<string>(undefined);
const [selectedPayload, setSelectedPayload] = useState(undefined);
@ -71,6 +72,14 @@ const WebhooksTemplateEditor: React.FC<WebhooksTemplateEditorProps> = ({ templat
}
};
const onShowCheatSheet = useCallback(() => {
setIsCheatSheetVisible(true);
}, []);
const onCloseCheatSheet = useCallback(() => {
setIsCheatSheetVisible(false);
}, []);
return (
<Drawer
title={
@ -119,8 +128,8 @@ const WebhooksTemplateEditor: React.FC<WebhooksTemplateEditorProps> = ({ templat
{isCheatSheetVisible ? (
<CheatSheet
cheatSheetName={template.displayName}
cheatSheetData={getCheatSheet(template.name)}
cheatSheetName="Generic"
cheatSheetData={genericTemplateCheatSheet}
onClose={onCloseCheatSheet}
/>
) : (
@ -129,10 +138,9 @@ const WebhooksTemplateEditor: React.FC<WebhooksTemplateEditorProps> = ({ templat
<div className={cx('template-editor-block-title')}>
<HorizontalGroup justify="space-between" align="center" wrap>
<Text>Template editor</Text>
{/* <Button variant="secondary" fill="outline" onClick={onShowCheatSheet} icon="book" size="sm">
<Button variant="secondary" fill="outline" onClick={onShowCheatSheet} icon="book" size="sm">
Cheatsheet
</Button> */}
</Button>
</HorizontalGroup>
</div>
<div className={cx('template-editor-block-content')}>
@ -163,14 +171,6 @@ const WebhooksTemplateEditor: React.FC<WebhooksTemplateEditorProps> = ({ templat
</div>
</Drawer>
);
// function onShowCheatSheet() {}
function onCloseCheatSheet() {}
function getCheatSheet(_templateName: string) {
return undefined;
}
};
export default WebhooksTemplateEditor;

View file

@ -2,7 +2,6 @@ export const getApiPathByPage = (page: string) => {
return (
{
outgoing_webhooks: 'custom_buttons',
outgoing_webhooks_2: 'webhooks',
incidents: 'alertgroups',
integrations: 'alert_receive_channels',
}[page] || page

View file

@ -97,15 +97,6 @@ export const pages: { [id: string]: PageDefinition } = [
hideFromTabs: isTopNavbar(),
action: UserActions.ChatOpsRead,
},
{
icon: 'link',
id: 'outgoing_webhooks_2',
text: 'Outgoing webhooks 2',
path: getPath('outgoing_webhooks_2'),
hideFromBreadcrumbs: true,
hideFromTabs: true,
action: UserActions.OutgoingWebhooksRead,
},
{
icon: 'wrench',
id: 'maintenance',
@ -177,8 +168,7 @@ export const ROUTES = {
escalations: ['escalations', 'escalations/:id'],
schedules: ['schedules'],
schedule: ['schedules/:id'],
outgoing_webhooks: ['outgoing_webhooks', 'outgoing_webhooks/:id'],
outgoing_webhooks_2: ['outgoing_webhooks_2', 'outgoing_webhooks_2/:id', 'outgoing_webhooks_2/:action/:id'],
outgoing_webhooks: ['outgoing_webhooks', 'outgoing_webhooks/:id', 'outgoing_webhooks/:action/:id'],
maintenance: ['maintenance'],
settings: ['settings'],
'chat-ops': ['chat-ops'],

View file

@ -10,10 +10,6 @@
align-items: baseline;
}
.header__desc {
margin-bottom: 12px;
}
.hamburgerMenu {
display: flex;
flex-direction: column;
@ -38,4 +34,4 @@
&:hover {
background: var(--cards-background);
}
}
}

View file

@ -177,20 +177,13 @@ class OutgoingWebhooks2 extends React.Component<OutgoingWebhooks2Props, Outgoing
title={() => (
<div className={cx('header')}>
<div className="header__title">
<VerticalGroup spacing="sm">
<LegacyNavHeading>
<Text.Title level={3}>Outgoing Webhooks 2</Text.Title>
</LegacyNavHeading>
<Text type="secondary" className={cx('header__desc')}>
<Icon name="exclamation-triangle"></Icon> Preview Functionality! Things will change and things
will break! Do not use for critical production processes!
</Text>
</VerticalGroup>
<LegacyNavHeading>
<Text.Title level={3}>Outgoing Webhooks</Text.Title>
</LegacyNavHeading>
</div>
<div className="u-pull-right">
<PluginLink
query={{ page: 'outgoing_webhooks_2', id: 'new' }}
query={{ page: 'outgoing_webhooks', id: 'new' }}
disabled={!isUserActionAllowed(UserActions.OutgoingWebhooksWrite)}
>
<WithPermissionControlTooltip userAction={UserActions.OutgoingWebhooksWrite}>
@ -217,7 +210,7 @@ class OutgoingWebhooks2 extends React.Component<OutgoingWebhooks2Props, Outgoing
onDelete={() => {
this.onDeleteClick(outgoingWebhook2Id).then(() => {
this.setState({ outgoingWebhook2Id: undefined, outgoingWebhook2Action: undefined });
history.push(`${PLUGIN_ROOT}/outgoing_webhooks_2`);
history.push(`${PLUGIN_ROOT}/outgoing_webhooks`);
});
}}
/>
@ -393,7 +386,7 @@ class OutgoingWebhooks2 extends React.Component<OutgoingWebhooks2Props, Outgoing
const { history } = this.props;
this.setState({ outgoingWebhook2Id: id, outgoingWebhook2Action: WebhookFormActionType.EDIT_SETTINGS }, () =>
history.push(`${PLUGIN_ROOT}/outgoing_webhooks_2/edit/${id}`)
history.push(`${PLUGIN_ROOT}/outgoing_webhooks/edit/${id}`)
);
};
@ -401,7 +394,7 @@ class OutgoingWebhooks2 extends React.Component<OutgoingWebhooks2Props, Outgoing
const { history } = this.props;
this.setState({ outgoingWebhook2Id: id, outgoingWebhook2Action: WebhookFormActionType.COPY }, () =>
history.push(`${PLUGIN_ROOT}/outgoing_webhooks_2/copy/${id}`)
history.push(`${PLUGIN_ROOT}/outgoing_webhooks/copy/${id}`)
);
};
@ -427,7 +420,7 @@ class OutgoingWebhooks2 extends React.Component<OutgoingWebhooks2Props, Outgoing
const { history } = this.props;
this.setState({ outgoingWebhook2Id: id, outgoingWebhook2Action: WebhookFormActionType.VIEW_LAST_RUN }, () =>
history.push(`${PLUGIN_ROOT}/outgoing_webhooks_2/last_run/${id}`)
history.push(`${PLUGIN_ROOT}/outgoing_webhooks/last_run/${id}`)
);
};
@ -436,7 +429,7 @@ class OutgoingWebhooks2 extends React.Component<OutgoingWebhooks2Props, Outgoing
this.setState({ outgoingWebhook2Id: undefined, outgoingWebhook2Action: undefined });
history.push(`${PLUGIN_ROOT}/outgoing_webhooks_2`);
history.push(`${PLUGIN_ROOT}/outgoing_webhooks`);
};
}

View file

@ -3,7 +3,6 @@ import IncidentPage from 'pages/incident/Incident';
import IncidentsPage from 'pages/incidents/Incidents';
import MaintenancePage from 'pages/maintenance/Maintenance';
import OutgoingWebhooks from 'pages/outgoing_webhooks/OutgoingWebhooks';
import OutgoingWebhooks2 from 'pages/outgoing_webhooks_2/OutgoingWebhooks2';
import SchedulePage from 'pages/schedule/Schedule';
import SchedulesPage from 'pages/schedules/Schedules';
import SettingsPage from 'pages/settings/SettingsPage';
@ -56,10 +55,6 @@ export const routes: { [id: string]: NavRoute } = [
component: OutgoingWebhooks,
id: 'outgoing_webhooks',
},
{
component: OutgoingWebhooks2,
id: 'outgoing_webhooks_2',
},
{
component: MaintenancePage,
id: 'maintenance',

View file

@ -86,14 +86,6 @@
"action": "grafana-oncall-app.outgoing-webhooks:read",
"addToNav": true
},
{
"type": "page",
"name": "Outgoing webhooks 2",
"path": "/a/grafana-oncall-app/outgoing_webhooks_2",
"role": "Viewer",
"action": "grafana-oncall-app.outgoing-webhooks:read",
"addToNav": false
},
{
"type": "page",
"name": "Maintenance",

View file

@ -37,6 +37,7 @@ import CloudPage from 'pages/settings/tabs/Cloud/CloudPage';
import LiveSettings from 'pages/settings/tabs/LiveSettings/LiveSettingsPage';
import Users from 'pages/users/Users';
import { rootStore } from 'state';
import { AppFeature } from 'state/features';
import { useStore } from 'state/useStore';
import { isUserActionAllowed } from 'utils/authorization';
import loadJs from 'utils/loadJs';
@ -163,10 +164,11 @@ export const Root = observer((props: AppRootProps) => {
<Schedule query={query} />
</Route>
<Route path={getRoutesForPage('outgoing_webhooks')} exact>
<OutgoingWebhooks query={query} />
</Route>
<Route path={getRoutesForPage('outgoing_webhooks_2')} exact>
<OutgoingWebhooks2 query={query} />
{rootStore.hasFeature(AppFeature.Webhooks2) ? (
<OutgoingWebhooks2 query={query} />
) : (
<OutgoingWebhooks query={query} />
)}
</Route>
<Route path={getRoutesForPage('maintenance')} exact>
<Maintenance />