Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 45 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,33 @@
# Appwrite's fork of Grafana OnCall

Grafana archived OnCall OSS on 2026-03-24. [Appwrite](https://appwrite.io) maintains this
fork for its own use — we keep it working for our needs, but offer no support or
roadmap commitments. Engine images are published to
[`ghcr.io/appwrite/grafana-oncall`](https://github.com/appwrite/grafana-oncall/pkgs/container/grafana-oncall).
Grafana archived [OnCall OSS](https://github.com/grafana/oncall) on 2026-03-24 at v1.16.11.
[Appwrite](https://appwrite.io) maintains this fork for its own use.

## What's different from upstream

- **It runs on current Grafana.** Grafana 13 ships React 19, which removed `ReactDOM.findDOMNode`.
Upstream's plugin reaches it through three libraries, so escalation chains, notification policies
and the rotation modals crash on mount. Fixed by moving drag-and-drop to `@dnd-kit`, passing
`nodeRef` to `react-draggable`, and replacing `react-transition-group` with a CSS animation.
- **Insights renders.** Its `alert_groups_total` variable was seeded multi-valued and URL-synced, so
a restored value interpolated a regex where PromQL wants a metric name, breaking every panel.
- **End-to-end tests run against Grafana 12 and 13**, where upstream tested 10 and 11.
- **~290 security patches.** Dependabot alerts went from 309 to 18.
- **Django 5.2 LTS**, where upstream is on 4.2 — its extended support ended in April 2026.
- **`fcm-django` from PyPI** rather than a tarball of a now-archived fork.
- **Releases ship both halves**: multi-arch engine images to
[`ghcr.io/appwrite/grafana-oncall`](https://github.com/appwrite/grafana-oncall/pkgs/container/grafana-oncall)
and a plugin archive attached to each
[release](https://github.com/appwrite/grafana-oncall/releases). Upstream's catalog build is frozen
at 1.16.11.

## What it does not offer

- No support and no roadmap commitments. We keep it working for our needs.
- The plugin is unsigned, since signing needs a grafana.com access policy, so it needs
`GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS=grafana-oncall-app`.
- The helm chart is not published to a helm repository; install it from a checkout.
- The mobile app relied on Grafana Cloud's push relay, which went away with the archival.

## Grafana OnCall

Expand Down Expand Up @@ -46,7 +70,7 @@ We prepared multiple environments:
1. Download [`docker-compose.yml`](docker-compose.yml):

```bash
curl -fsSL https://raw.githubusercontent.com/grafana/oncall/dev/docker-compose.yml -o docker-compose.yml
curl -fsSL https://raw.githubusercontent.com/appwrite/grafana-oncall/main/docker-compose.yml -o docker-compose.yml
```

2. Set variables:
Expand Down Expand Up @@ -128,36 +152,38 @@ Here are some API calls that can be made to help if you are having difficulty co

## Update version

To update your Grafana OnCall hobby environment:
The engine and plugin are released together and are not meant to be mixed across versions, so one
variable moves both. Set it to the [release](https://github.com/appwrite/grafana-oncall/releases) you
want in `.env`:

```shell
# Update Docker image
docker-compose pull engine
echo "ONCALL_VERSION=1.19.1" >> .env

# Re-deploy
docker-compose pull
docker-compose up -d
```

After updating the engine, you'll also need to click the "Update" button on the [plugin version page](http://localhost:3000/plugins/grafana-oncall-app?page=version-history).
See [Grafana docs](https://grafana.com/docs/grafana/latest/administration/plugin-management/#update-a-plugin) for more
info on updating Grafana plugins.
The plugin is not in the grafana.com catalog, so it does not update through the plugin page. Grafana
only installs a plugin that is not already present, so to move the plugin you also have to clear the
old copy from its volume:

```shell
docker-compose exec grafana rm -rf /var/lib/grafana/plugins/grafana-oncall-app
docker-compose restart grafana
```

## Join community

[<img width="200px" src="docs/img/slack.png">](https://slack.grafana.com/)
[<img width="200px" src="docs/img/GH_discussions.png">](https://community.grafana.com/)

Have a question, comment or feedback? Don't be afraid to [open an issue](https://github.com/grafana/oncall/issues/new/choose)!

## Stargazers over time

[![Stargazers over time](https://starchart.cc/grafana/oncall.svg)](https://starchart.cc/grafana/oncall)
Have a question, comment or feedback? Don't be afraid to [open an issue](https://github.com/appwrite/grafana-oncall/issues/new/choose)!

## Further Reading

- _Automated migration from other on-call tools_ - [Migrator](https://github.com/grafana/oncall/tree/dev/tools/migrators)
- _Automated migration from other on-call tools_ - [Migrator](https://github.com/appwrite/grafana-oncall/tree/main/tools/migrators)
- _Documentation_ - [Grafana OnCall](https://grafana.com/docs/oncall/latest/)
- _Overview Webinar_ - [YouTube](https://www.youtube.com/watch?v=7uSe1pulgs8)
- _How To Add Integration_ - [How to Add Integration](https://github.com/grafana/oncall/tree/dev/engine/config_integrations/README.md)
- _How To Add Integration_ - [How to Add Integration](https://github.com/appwrite/grafana-oncall/tree/main/engine/config_integrations/README.md)
- _Blog Post_ - [Announcing Grafana OnCall, the easiest way to do on-call management](https://grafana.com/blog/2021/11/09/announcing-grafana-oncall/)
- _Presentation_ - [Deep dive into the Grafana, Prometheus, and Alertmanager stack for alerting and on-call management](https://grafana.com/go/observabilitycon/2021/alerting/?pg=blog)
3 changes: 1 addition & 2 deletions docker-compose-developer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ x-oncall-build: &oncall-build-args
target: ${ONCALL_IMAGE_TARGET:-dev}
labels: *oncall-labels
cache_from:
- grafana/oncall:latest
- grafana/oncall:dev
- ghcr.io/appwrite/grafana-oncall:latest

x-oncall-volumes: &oncall-volumes
- ./engine:/etc/app
Expand Down
12 changes: 8 additions & 4 deletions docker-compose-mysql-rabbitmq.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ x-environment: &oncall-environment

services:
engine:
image: grafana/oncall
image: ghcr.io/appwrite/grafana-oncall:v${ONCALL_VERSION:-1.19.1}
restart: always
ports:
- "8080:8080"
Expand All @@ -39,7 +39,7 @@ services:
condition: service_started

celery:
image: grafana/oncall
image: ghcr.io/appwrite/grafana-oncall:v${ONCALL_VERSION:-1.19.1}
restart: always
command: sh -c "./celery_with_exporter.sh"
environment: *oncall-environment
Expand All @@ -54,7 +54,7 @@ services:
condition: service_started

oncall_db_migration:
image: grafana/oncall
image: ghcr.io/appwrite/grafana-oncall:v${ONCALL_VERSION:-1.19.1}
command: python manage.py migrate --noinput
environment: *oncall-environment
depends_on:
Expand Down Expand Up @@ -143,7 +143,11 @@ services:
GF_SECURITY_ADMIN_USER: ${GRAFANA_USER:-admin}
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD:-admin}
GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS: grafana-oncall-app
GF_INSTALL_PLUGINS: grafana-oncall-app
# The catalog build is grafana's archived one, so install this fork's plugin archive.
# ONCALL_VERSION pins the engine too: the plugin and engine are released together
# and are not meant to be mixed across versions.
# yamllint disable-line rule:line-length
GF_INSTALL_PLUGINS: https://github.com/appwrite/grafana-oncall/releases/download/v${ONCALL_VERSION:-1.19.1}/grafana-oncall-app-${ONCALL_VERSION:-1.19.1}.zip;grafana-oncall-app
GF_AUTH_MANAGED_SERVICE_ACCOUNTS_ENABLED: true
deploy:
resources:
Expand Down
12 changes: 8 additions & 4 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ x-environment: &oncall-environment

services:
engine:
image: grafana/oncall
image: ghcr.io/appwrite/grafana-oncall:v${ONCALL_VERSION:-1.19.1}
restart: always
ports:
- "8080:8080"
Expand All @@ -31,7 +31,7 @@ services:
condition: service_healthy

celery:
image: grafana/oncall
image: ghcr.io/appwrite/grafana-oncall:v${ONCALL_VERSION:-1.19.1}
restart: always
command: sh -c "./celery_with_exporter.sh"
environment: *oncall-environment
Expand All @@ -44,7 +44,7 @@ services:
condition: service_healthy

oncall_db_migration:
image: grafana/oncall
image: ghcr.io/appwrite/grafana-oncall:v${ONCALL_VERSION:-1.19.1}
command: python manage.py migrate --noinput
environment: *oncall-environment
volumes:
Expand Down Expand Up @@ -93,7 +93,11 @@ services:
GF_SECURITY_ADMIN_USER: ${GRAFANA_USER:-admin}
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD:-admin}
GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS: grafana-oncall-app
GF_INSTALL_PLUGINS: grafana-oncall-app
# The catalog build is grafana's archived one, so install this fork's plugin archive.
# ONCALL_VERSION pins the engine too: the plugin and engine are released together
# and are not meant to be mixed across versions.
# yamllint disable-line rule:line-length
GF_INSTALL_PLUGINS: https://github.com/appwrite/grafana-oncall/releases/download/v${ONCALL_VERSION:-1.19.1}/grafana-oncall-app-${ONCALL_VERSION:-1.19.1}.zip;grafana-oncall-app
GF_AUTH_MANAGED_SERVICE_ACCOUNTS_ENABLED: true
volumes:
- grafana_data:/var/lib/grafana
Expand Down
4 changes: 2 additions & 2 deletions helm/oncall/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ apiVersion: v2
name: oncall
description: Developer-friendly incident response with brilliant Slack integration
type: application
version: 1.15.6
appVersion: v1.15.6
version: 1.19.1
appVersion: v1.19.1
dependencies:
- name: cert-manager
version: v1.8.0
Expand Down
37 changes: 23 additions & 14 deletions helm/oncall/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ It will deploy Grafana OnCall engine and celery workers, along with RabbitMQ clu
It will also deploy cert manager and nginx ingress controller, as Grafana OnCall backend might need to be externally available
to receive alerts from other monitoring systems. Grafana OnCall engine acts as a backend and can be connected to the
Grafana frontend plugin named Grafana OnCall.
Architecture diagram can be found [here](https://raw.githubusercontent.com/grafana/oncall/dev/docs/img/architecture_diagram.png)
Architecture diagram can be found [here](https://raw.githubusercontent.com/appwrite/grafana-oncall/main/docs/img/architecture_diagram.png)

## Production usage

Expand All @@ -23,12 +23,13 @@ Here are the instructions on how to set up your own [ingress](#set-up-external-a

## Install

### Prepare the repo
### Prepare the chart

This chart is not published to a helm repository, so install it from a checkout:

```bash
# Add the repository
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
git clone https://github.com/appwrite/grafana-oncall.git
cd grafana-oncall
```

### Installing the helm chart
Expand All @@ -40,7 +41,7 @@ helm install \
--set base_url=example.com \
--set grafana."grafana\.ini".server.domain=example.com \
release-oncall \
grafana/oncall
./helm/oncall
```

Follow the `helm install` output to finish setting up Grafana OnCall backend and Grafana OnCall frontend plugin e.g.
Expand Down Expand Up @@ -83,7 +84,7 @@ helm upgrade \
--set base_url=example.com \
--set grafana."grafana\.ini".server.domain=example.com \
release-oncall \
grafana/oncall
./helm/oncall
```

### Passwords and external secrets
Expand Down Expand Up @@ -382,9 +383,8 @@ externalRedis:
## Update

```bash
Comment thread
greptile-apps[bot] marked this conversation as resolved.
# Add & upgrade the repository
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
# Pull the latest chart
git pull

# Re-deploy
helm upgrade \
Expand All @@ -393,12 +393,21 @@ helm upgrade \
--set base_url=example.com \
--set grafana."grafana\.ini".server.domain=example.com \
release-oncall \
grafana/oncall
./helm/oncall
```

After re-deploying, please also update the Grafana OnCall plugin on the plugin version page.
See [Grafana docs](https://grafana.com/docs/grafana/latest/administration/plugin-management/#update-a-plugin) for
more info on updating Grafana plugins.
The plugin is not in the grafana.com catalog, so it does not update through the plugin page. The
bundled Grafana installs it from this fork's release archive, and the chart derives that version from
`image.tag` (falling back to the chart's `appVersion`) — so bumping the engine moves the plugin with
it, and the two cannot end up on different versions.

Grafana only installs a plugin that is not already present, so with `grafana.persistence` enabled the
old copy has to be cleared before it will reinstall:

```bash
kubectl exec deploy/release-oncall-grafana -- rm -rf /var/lib/grafana/plugins/grafana-oncall-app
kubectl rollout restart deploy/release-oncall-grafana
```

## Uninstall

Expand Down
19 changes: 19 additions & 0 deletions helm/oncall/templates/grafana-plugin-env.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{{- if .Values.grafana.enabled }}
{{/*
The plugin is not in the grafana.com catalog, so the bundled Grafana installs it from this fork's
release archive. The version is taken from the same expression as the engine image, so overriding
image.tag moves both halves: they are released together and are not meant to be mixed.

This is a ConfigMap because subchart values cannot be templated — grafana.envValueFrom points at
it, and the grafana chart runs tpl over that block so it can resolve the release-scoped name.
*/}}
{{- $version := .Values.image.tag | default .Chart.AppVersion }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-oncall-plugin
labels:
app: {{ include "oncall.name" . }}
data:
GF_INSTALL_PLUGINS: https://github.com/appwrite/grafana-oncall/releases/download/{{ $version }}/grafana-oncall-app-{{ trimPrefix "v" $version }}.zip;grafana-oncall-app
{{- end }}
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ detached_integrations.enabled=true -> should create integrations deployment:
value: ""
- name: ROOT_URLCONF
value: engine.integrations_urls
image: grafana/oncall:v1.3.39
image: ghcr.io/appwrite/grafana-oncall:v1.3.39
imagePullPolicy: Always
livenessProbe:
httpGet:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ telegramPolling.enabled=true -> should create telegram polling deployment:
value: amqp
- name: RABBITMQ_VHOST
value: ""
image: grafana/oncall:v1.2.36
image: ghcr.io/appwrite/grafana-oncall:v1.2.36
imagePullPolicy: Always
name: telegram-polling
securityContext: {}
12 changes: 6 additions & 6 deletions helm/oncall/tests/__snapshot__/wait_for_db_test.yaml.snap
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ database.type=mysql -> should create initContainer for MySQL database (default):
value: amqp
- name: RABBITMQ_VHOST
value: ""
image: grafana/oncall:v1.2.36
image: ghcr.io/appwrite/grafana-oncall:v1.2.36
imagePullPolicy: Always
name: wait-for-db
resources:
Expand Down Expand Up @@ -164,7 +164,7 @@ database.type=mysql -> should create initContainer for MySQL database (default):
value: amqp
- name: RABBITMQ_VHOST
value: ""
image: grafana/oncall:v1.2.36
image: ghcr.io/appwrite/grafana-oncall:v1.2.36
imagePullPolicy: Always
name: wait-for-db
resources:
Expand Down Expand Up @@ -252,7 +252,7 @@ database.type=mysql -> should create initContainer for MySQL database (default):
value: amqp
- name: RABBITMQ_VHOST
value: ""
image: grafana/oncall:v1.2.36
image: ghcr.io/appwrite/grafana-oncall:v1.2.36
imagePullPolicy: Always
name: wait-for-db
resources:
Expand Down Expand Up @@ -343,7 +343,7 @@ database.type=postgresql -> should create initContainer for PostgreSQL database:
value: amqp
- name: RABBITMQ_VHOST
value: ""
image: grafana/oncall:v1.2.36
image: ghcr.io/appwrite/grafana-oncall:v1.2.36
imagePullPolicy: Always
name: wait-for-db
resources:
Expand Down Expand Up @@ -433,7 +433,7 @@ database.type=postgresql -> should create initContainer for PostgreSQL database:
value: amqp
- name: RABBITMQ_VHOST
value: ""
image: grafana/oncall:v1.2.36
image: ghcr.io/appwrite/grafana-oncall:v1.2.36
imagePullPolicy: Always
name: wait-for-db
resources:
Expand Down Expand Up @@ -523,7 +523,7 @@ database.type=postgresql -> should create initContainer for PostgreSQL database:
value: amqp
- name: RABBITMQ_VHOST
value: ""
image: grafana/oncall:v1.2.36
image: ghcr.io/appwrite/grafana-oncall:v1.2.36
imagePullPolicy: Always
name: wait-for-db
resources:
Expand Down
2 changes: 1 addition & 1 deletion helm/oncall/tests/image_deployments_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ tests:
asserts:
- equal:
path: spec.template.spec.containers[0].image
value: grafana/oncall:1.2.36
value: ghcr.io/appwrite/grafana-oncall:1.2.36
- equal:
path: spec.template.spec.containers[0].imagePullPolicy
value: Always
Expand Down
Loading
Loading