commit
3ec23afea0
59 changed files with 1470 additions and 283 deletions
10
.github/CODEOWNERS
vendored
10
.github/CODEOWNERS
vendored
|
|
@ -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
|
||||
|
|
|
|||
3
.github/workflows/linting-and-tests.yml
vendored
3
.github/workflows/linting-and-tests.yml
vendored
|
|
@ -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
27
.github/workflows/update-make-docs.yml
vendored
Normal 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 }}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
10
CHANGELOG.md
10
CHANGELOG.md
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -4,5 +4,8 @@
|
|||
"line_length": "160"
|
||||
},
|
||||
"MD025": false,
|
||||
"MD036": false
|
||||
"MD033": false,
|
||||
"MD036": false,
|
||||
"MD052": false,
|
||||
"MD053": false
|
||||
}
|
||||
|
|
|
|||
19
docs/docs.mk
19
docs/docs.mk
|
|
@ -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.
|
||||
|
|
|
|||
219
docs/make-docs
219
docs/make-docs
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 %}}
|
||||
|
|
|
|||
|
|
@ -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 %}}
|
||||
|
|
|
|||
|
|
@ -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 %}}
|
||||
|
|
|
|||
|
|
@ -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 isn’t 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 %}}
|
||||
|
|
|
|||
|
|
@ -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 %}}
|
||||
|
|
|
|||
|
|
@ -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 %}}
|
||||
|
|
|
|||
|
|
@ -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 %}}
|
||||
|
|
|
|||
|
|
@ -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 %}}
|
||||
|
|
|
|||
|
|
@ -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 %}}
|
||||
|
|
|
|||
|
|
@ -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 %}}
|
||||
|
|
|
|||
|
|
@ -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 %}}
|
||||
|
|
|
|||
|
|
@ -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 %}}
|
||||
|
|
|
|||
|
|
@ -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 %}}
|
||||
|
|
|
|||
|
|
@ -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 %}}
|
||||
|
|
|
|||
|
|
@ -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 %}}
|
||||
|
|
|
|||
|
|
@ -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 %}}
|
||||
|
|
|
|||
|
|
@ -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 %}}
|
||||
|
|
|
|||
140
docs/sources/integrations/servicenow/index.md
Normal file
140
docs/sources/integrations/servicenow/index.md
Normal 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).
|
||||
|
|
@ -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 %}}
|
||||
|
|
|
|||
|
|
@ -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 %}}
|
||||
|
|
|
|||
|
|
@ -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 %}}
|
||||
|
|
|
|||
|
|
@ -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 %}}
|
||||
|
|
|
|||
|
|
@ -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 %}}
|
||||
|
|
|
|||
|
|
@ -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 %}}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ To install the Slack integration, you must have Admin permissions in your Grafan
|
|||
that you’d 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 %}}
|
||||
|
|
|
|||
|
|
@ -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 %}}
|
||||
|
|
|
|||
|
|
@ -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 %}}
|
||||
|
|
|
|||
|
|
@ -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 %}}
|
||||
|
|
|
|||
|
|
@ -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 %}}
|
||||
|
|
|
|||
|
|
@ -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 >}}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
77
engine/apps/webhooks/migrations/0008_auto_20230712_1613.py
Normal file
77
engine/apps/webhooks/migrations/0008_auto_20230712_1613.py
Normal 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)
|
||||
]
|
||||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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: {},
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
) : (
|
||||
''
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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'],
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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`);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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 />
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue