Telegram long polling (#2250)
# What this PR does Runs Telegram long polling to get updates. It's enabled by setting `FEATURE_TELEGRAM_LONG_POLLING_ENABLED=True`. That will disable webhook and run separate deployment for telegram long polling. Telegram long polling is not very HA mode, but it does not need to expose webhook url to internet and simplifies telegram integration. ## Which issue(s) this PR fixes closes #561 ## Checklist - [x] Unit, integration, and e2e (if applicable) tests updated - [x] Documentation added (or `pr:no public docs` PR label added if not required) - [x] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not required)
This commit is contained in:
parent
5a5fb6ea8e
commit
ec028eb9d9
32 changed files with 586 additions and 7 deletions
|
|
@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
### Added
|
||||
|
||||
- Public API for webhooks @mderynck ([#2790](https://github.com/grafana/oncall/pull/2790))
|
||||
- Use Telegram polling protocol instead of a webhook if `FEATURE_TELEGRAM_LONG_POLLING_ENABLED` set to `True` by @alexintech
|
||||
([#2250](https://github.com/grafana/oncall/pull/2250))
|
||||
|
||||
### Changed
|
||||
|
||||
|
|
|
|||
1
Makefile
1
Makefile
|
|
@ -18,6 +18,7 @@ REDIS_PROFILE = redis
|
|||
RABBITMQ_PROFILE = rabbitmq
|
||||
PROMETHEUS_PROFILE = prometheus
|
||||
GRAFANA_PROFILE = grafana
|
||||
TELEGRAM_POLLING_PROFILE = telegram_polling
|
||||
|
||||
DEV_ENV_DIR = ./dev
|
||||
DEV_ENV_FILE = $(DEV_ENV_DIR)/.env.dev
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ SOCIAL_AUTH_REDIRECT_IS_HTTPS=False
|
|||
GRAFANA_INCIDENT_STATIC_API_KEY=
|
||||
GRAFANA_API_URL=http://localhost:3000
|
||||
|
||||
CELERY_WORKER_QUEUE="default,critical,long,slack,telegram,webhook,retry,celery"
|
||||
CELERY_WORKER_QUEUE=default,critical,long,slack,telegram,webhook,retry,celery
|
||||
CELERY_WORKER_CONCURRENCY=3
|
||||
CELERY_WORKER_MAX_TASKS_PER_CHILD=100
|
||||
CELERY_WORKER_SHUTDOWN_INTERVAL=65m
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ The possible profiles values are:
|
|||
- `rabbitmq`
|
||||
- `postgres`
|
||||
- `mysql`
|
||||
- `telegram_polling`
|
||||
|
||||
The default is `engine,oncall_ui,redis,grafana`. This runs:
|
||||
|
||||
|
|
|
|||
|
|
@ -81,6 +81,23 @@ services:
|
|||
profiles:
|
||||
- engine
|
||||
|
||||
oncall_telegram_polling:
|
||||
container_name: oncall_telegram_polling
|
||||
labels: *oncall-labels
|
||||
build: *oncall-build-args
|
||||
restart: always
|
||||
user: *oncall-user
|
||||
command: sh -c "python manage.py start_telegram_polling"
|
||||
env_file: *oncall-env-files
|
||||
environment: *oncall-env-vars
|
||||
volumes: *oncall-volumes
|
||||
extra_hosts: *oncall-extra-hosts
|
||||
depends_on:
|
||||
oncall_db_migration:
|
||||
condition: service_completed_successfully
|
||||
profiles:
|
||||
- telegram_polling
|
||||
|
||||
# used to invoke one-off commands, primarily from the Makefile
|
||||
# oncall_engine couldn't (easily) be used due to it's depends_on property
|
||||
# we could alternatively just use `docker run` however that would require
|
||||
|
|
|
|||
|
|
@ -178,18 +178,20 @@ frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media
|
|||
web-share" allowfullscreen></iframe>
|
||||
|
||||
The Telegram integration for Grafana OnCall is designed for collaborative team work and improved incident response.
|
||||
It's available in two options: using Webhooks or Long Polling.
|
||||
Refer to the following steps to configure the Telegram integration:
|
||||
|
||||
1. Ensure your Grafana OnCall environment is up and running.
|
||||
2. Set `FEATURE_TELEGRAM_INTEGRATION_ENABLED` as "True"
|
||||
3. Create a Telegram bot using [BotFather](https://t.me/BotFather) and save the token provided by BotFather. Please make
|
||||
3. (Long Polling only) Set `FEATURE_TELEGRAM_LONG_POLLING_ENABLED` as "True"
|
||||
4. Create a Telegram bot using [BotFather](https://t.me/BotFather) and save the token provided by BotFather. Please make
|
||||
sure to disable **Group Privacy** for the bot (Bot Settings -> Group Privacy -> Turn off).
|
||||
4. Paste the token provided by BotFather to the `TELEGRAM_TOKEN` variable on the **Env Variables** page of your
|
||||
5. Paste the token provided by BotFather to the `TELEGRAM_TOKEN` variable on the **Env Variables** page of your
|
||||
Grafana OnCall instance.
|
||||
5. Set the `TELEGRAM_WEBHOOK_HOST` variable to the external address of your Grafana OnCall instance. Please note
|
||||
6. (Webhook only) Set the `TELEGRAM_WEBHOOK_HOST` variable to the external address of your Grafana OnCall instance. Please note
|
||||
that `TELEGRAM_WEBHOOK_HOST` must start with `https://` and be publicly available (meaning that it can be reached by
|
||||
Telegram servers). If your host is private or local, consider using a reverse proxy (e.g. [ngrok](https://ngrok.com)).
|
||||
6. Now you can connect Telegram accounts on the **Users** page and receive alert groups to Telegram direct messages.
|
||||
7. Now you can connect Telegram accounts on the **Users** page and receive alert groups to Telegram direct messages.
|
||||
Alternatively, in case you want to connect Telegram channels to your Grafana OnCall environment, navigate
|
||||
to the **ChatOps** tab.
|
||||
|
||||
|
|
|
|||
|
|
@ -160,3 +160,33 @@ def test_live_settings_telegram_calls_set_webhook_once(
|
|||
mock_set_webhook.assert_called_once_with(
|
||||
"TEST_UPDATED_VALUE/telegram/", allowed_updates=("message", "callback_query")
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_live_settings_telegram_set_webhook_not_called_if_long_polling_enabled(
|
||||
make_organization_and_user_with_plugin_token,
|
||||
make_user_auth_headers,
|
||||
make_live_setting,
|
||||
settings,
|
||||
):
|
||||
"""
|
||||
Check that when FEATURE_TELEGRAM_LONG_POLLING_ENABLED is true setting webhook with updating
|
||||
TELEGRAM_WEBHOOK_HOST live setting does not evaluate.
|
||||
"""
|
||||
|
||||
settings.FEATURE_LIVE_SETTINGS_ENABLED = True
|
||||
settings.FEATURE_TELEGRAM_LONG_POLLING_ENABLED = True
|
||||
|
||||
organization, user, token = make_organization_and_user_with_plugin_token()
|
||||
LiveSetting.populate_settings_if_needed()
|
||||
live_setting = LiveSetting.objects.get(name="TELEGRAM_WEBHOOK_HOST")
|
||||
|
||||
client = APIClient()
|
||||
url = reverse("api-internal:live_settings-detail", kwargs={"pk": live_setting.public_primary_key})
|
||||
data = {"id": live_setting.public_primary_key, "value": "TEST_UPDATED_VALUE", "name": "TELEGRAM_WEBHOOK_HOST"}
|
||||
|
||||
with mock.patch("telegram.Bot.set_webhook") as mock_set_webhook:
|
||||
response = client.put(url, data=data, format="json", **make_user_auth_headers(user, token))
|
||||
|
||||
assert response.status_code == HTTP_200_OK
|
||||
mock_set_webhook.assert_not_called()
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import re
|
|||
from urllib.parse import urlparse
|
||||
|
||||
import phonenumbers
|
||||
from django.conf import settings
|
||||
from phonenumbers import NumberParseException
|
||||
from telegram import Bot
|
||||
from twilio.base.exceptions import TwilioException
|
||||
|
|
@ -137,6 +138,9 @@ class LiveSettingValidator:
|
|||
|
||||
@classmethod
|
||||
def _check_telegram_webhook_host(cls, telegram_webhook_host):
|
||||
if settings.FEATURE_TELEGRAM_LONG_POLLING_ENABLED:
|
||||
return
|
||||
|
||||
try:
|
||||
# avoid circular import
|
||||
from apps.telegram.client import TelegramClient
|
||||
|
|
|
|||
|
|
@ -46,6 +46,13 @@ class TelegramClient:
|
|||
|
||||
self.api_client.set_webhook(webhook_url, allowed_updates=self.ALLOWED_UPDATES)
|
||||
|
||||
def delete_webhook(self):
|
||||
webhook_info = self.api_client.get_webhook_info()
|
||||
if webhook_info.url == "":
|
||||
return
|
||||
|
||||
self.api_client.delete_webhook()
|
||||
|
||||
def send_message(
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@ logger.setLevel(logging.DEBUG)
|
|||
)
|
||||
@handle_missing_token
|
||||
def register_telegram_webhook(token=None):
|
||||
if settings.FEATURE_TELEGRAM_LONG_POLLING_ENABLED:
|
||||
return
|
||||
|
||||
telegram_client = TelegramClient(token=token)
|
||||
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -57,7 +57,8 @@ def on_after_setup_logger(logger, **kwargs):
|
|||
def on_worker_ready(*args, **kwargs):
|
||||
from apps.telegram.tasks import register_telegram_webhook
|
||||
|
||||
register_telegram_webhook.delay()
|
||||
if not settings.FEATURE_TELEGRAM_LONG_POLLING_ENABLED:
|
||||
register_telegram_webhook.delay()
|
||||
|
||||
|
||||
if settings.OTEL_TRACING_ENABLED and settings.OTEL_EXPORTER_OTLP_ENDPOINT:
|
||||
|
|
|
|||
50
engine/engine/management/commands/start_telegram_polling.py
Normal file
50
engine/engine/management/commands/start_telegram_polling.py
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import logging
|
||||
|
||||
import telegram.error
|
||||
from django.core.management.base import BaseCommand
|
||||
from telegram.ext import CallbackQueryHandler, Filters, MessageHandler, Updater
|
||||
|
||||
from apps.telegram.client import TelegramClient
|
||||
from apps.telegram.updates.update_manager import UpdateManager
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
|
||||
def start_telegram_polling():
|
||||
telegram_client = TelegramClient()
|
||||
|
||||
telegram_client.delete_webhook()
|
||||
|
||||
updater = Updater(token=telegram_client.token, use_context=True)
|
||||
|
||||
# Register the error handler function with the dispatcher
|
||||
updater.dispatcher.add_error_handler(error_handler)
|
||||
|
||||
callback_handler = CallbackQueryHandler(handle_message)
|
||||
|
||||
# register the message handler function with the dispatcher
|
||||
updater.dispatcher.add_handler(MessageHandler(Filters.text, handle_message))
|
||||
updater.dispatcher.add_handler(callback_handler)
|
||||
|
||||
# start the long polling loop
|
||||
updater.start_polling()
|
||||
|
||||
|
||||
def error_handler(update, context):
|
||||
try:
|
||||
raise context.error
|
||||
except telegram.error.Conflict as e:
|
||||
logger.warning(f"Tried to getUpdates() using telegram long polling, but conflict exists, got error: {e}")
|
||||
|
||||
|
||||
def handle_message(update, context):
|
||||
logger.debug(f"Update from Telegram: {update}")
|
||||
|
||||
UpdateManager.process_update(update)
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
def handle(self, *args, **options):
|
||||
logger.info("Starting telegram polling...")
|
||||
start_telegram_polling()
|
||||
|
|
@ -59,6 +59,7 @@ BASE_URL = os.environ.get("BASE_URL") # Root URL of OnCall backend
|
|||
# Feature toggles
|
||||
FEATURE_LIVE_SETTINGS_ENABLED = getenv_boolean("FEATURE_LIVE_SETTINGS_ENABLED", default=True)
|
||||
FEATURE_TELEGRAM_INTEGRATION_ENABLED = getenv_boolean("FEATURE_TELEGRAM_INTEGRATION_ENABLED", default=True)
|
||||
FEATURE_TELEGRAM_LONG_POLLING_ENABLED = getenv_boolean("FEATURE_TELEGRAM_LONG_POLLING_ENABLED", default=False)
|
||||
FEATURE_EMAIL_INTEGRATION_ENABLED = getenv_boolean("FEATURE_EMAIL_INTEGRATION_ENABLED", default=True)
|
||||
FEATURE_SLACK_INTEGRATION_ENABLED = getenv_boolean("FEATURE_SLACK_INTEGRATION_ENABLED", default=True)
|
||||
FEATURE_MULTIREGION_ENABLED = getenv_boolean("FEATURE_MULTIREGION_ENABLED", default=False)
|
||||
|
|
|
|||
|
|
@ -214,7 +214,7 @@ oncall:
|
|||
`oncall.slack.commandName` is used for changing default bot slash command,
|
||||
`oncall`. In slack, it could be called via `/<oncall.slack.commandName>`.
|
||||
|
||||
To set up Telegram tokem and webhook url use:
|
||||
To set up Telegram token and webhook url use:
|
||||
|
||||
```yaml
|
||||
oncall:
|
||||
|
|
@ -224,6 +224,13 @@ oncall:
|
|||
webhookUrl: ~
|
||||
```
|
||||
|
||||
To use Telegram long polling instead of webhook use:
|
||||
|
||||
```yaml
|
||||
telegramPolling:
|
||||
enabled: true
|
||||
```
|
||||
|
||||
### Set up external access
|
||||
|
||||
Grafana OnCall can be connected to the external monitoring systems or grafana deployed to the other cluster.
|
||||
|
|
|
|||
|
|
@ -95,9 +95,16 @@
|
|||
{{- end }}
|
||||
|
||||
{{- define "snippet.oncall.telegram.env" -}}
|
||||
{{- if .Values.telegramPolling.enabled -}}
|
||||
{{- $_ := set .Values.oncall.telegram "enabled" true -}}
|
||||
{{- end -}}
|
||||
- name: FEATURE_TELEGRAM_INTEGRATION_ENABLED
|
||||
value: {{ .Values.oncall.telegram.enabled | toString | title | quote }}
|
||||
{{- if .Values.oncall.telegram.enabled }}
|
||||
{{- if .Values.telegramPolling.enabled }}
|
||||
- name: FEATURE_TELEGRAM_LONG_POLLING_ENABLED
|
||||
value: {{ .Values.telegramPolling.enabled | toString | title | quote }}
|
||||
{{- end }}
|
||||
- name: TELEGRAM_WEBHOOK_HOST
|
||||
value: {{ .Values.oncall.telegram.webhookUrl | default (printf "https://%s" .Values.base_url) | quote }}
|
||||
{{- if .Values.oncall.telegram.existingSecret }}
|
||||
|
|
|
|||
22
helm/oncall/templates/telegram-polling/_helpers.tpl
Normal file
22
helm/oncall/templates/telegram-polling/_helpers.tpl
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{{/*
|
||||
Maximum of 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
*/}}
|
||||
{{- define "oncall.telegramPolling.fullname" -}}
|
||||
{{ include "oncall.fullname" . | trunc 45 }}-telegram-polling
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Telegram polling common labels
|
||||
*/}}
|
||||
{{- define "oncall.telegramPolling.labels" -}}
|
||||
{{ include "oncall.labels" . }}
|
||||
app.kubernetes.io/component: telegram-polling
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Telegram polling selector labels
|
||||
*/}}
|
||||
{{- define "oncall.telegramPolling.selectorLabels" -}}
|
||||
{{ include "oncall.selectorLabels" . }}
|
||||
app.kubernetes.io/component: telegram-polling
|
||||
{{- end }}
|
||||
44
helm/oncall/templates/telegram-polling/deployment.yaml
Normal file
44
helm/oncall/templates/telegram-polling/deployment.yaml
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
{{- if .Values.telegramPolling.enabled -}}
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "oncall.telegramPolling.fullname" . }}
|
||||
labels:
|
||||
{{- include "oncall.telegramPolling.labels" . | nindent 4 }}
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "oncall.telegramPolling.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "oncall.telegramPolling.selectorLabels" . | nindent 8 }}
|
||||
spec:
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "oncall.serviceAccountName" . }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||
initContainers:
|
||||
{{- include "oncall.initContainer" . | nindent 8 }}
|
||||
containers:
|
||||
- name: telegram-polling
|
||||
securityContext:
|
||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
command: ['sh', '-c', 'python manage.py start_telegram_polling']
|
||||
env:
|
||||
{{- include "snippet.oncall.env" . | nindent 12 }}
|
||||
{{- include "snippet.oncall.telegram.env" . | nindent 12 }}
|
||||
{{- include "snippet.db.env" . | nindent 12 }}
|
||||
{{- include "snippet.broker.env" . | nindent 12 }}
|
||||
{{- include "oncall.extraEnvs" . | nindent 12 }}
|
||||
{{- with .Values.telegramPolling.resources }}
|
||||
resources:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
telegramPolling.enabled=true -> should create telegram polling deployment:
|
||||
1: |
|
||||
- command:
|
||||
- sh
|
||||
- -c
|
||||
- python manage.py start_telegram_polling
|
||||
env:
|
||||
- name: BASE_URL
|
||||
value: https://example.com
|
||||
- name: SECRET_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
key: SECRET_KEY
|
||||
name: oncall
|
||||
- name: MIRAGE_SECRET_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
key: MIRAGE_SECRET_KEY
|
||||
name: oncall
|
||||
- name: MIRAGE_CIPHER_IV
|
||||
value: 1234567890abcdef
|
||||
- name: DJANGO_SETTINGS_MODULE
|
||||
value: settings.helm
|
||||
- name: AMIXR_DJANGO_ADMIN_PATH
|
||||
value: admin
|
||||
- name: OSS
|
||||
value: "True"
|
||||
- name: UWSGI_LISTEN
|
||||
value: "1024"
|
||||
- name: BROKER_TYPE
|
||||
value: rabbitmq
|
||||
- name: GRAFANA_API_URL
|
||||
value: http://oncall-grafana
|
||||
- name: FEATURE_TELEGRAM_INTEGRATION_ENABLED
|
||||
value: "True"
|
||||
- name: FEATURE_TELEGRAM_LONG_POLLING_ENABLED
|
||||
value: "True"
|
||||
- name: TELEGRAM_WEBHOOK_HOST
|
||||
value: https://example.com
|
||||
- name: TELEGRAM_TOKEN
|
||||
value: ""
|
||||
- name: MYSQL_HOST
|
||||
value: oncall-mariadb
|
||||
- name: MYSQL_PORT
|
||||
value: "3306"
|
||||
- name: MYSQL_DB_NAME
|
||||
value: oncall
|
||||
- name: MYSQL_USER
|
||||
value: root
|
||||
- name: MYSQL_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
key: mariadb-root-password
|
||||
name: oncall-mariadb
|
||||
- name: RABBITMQ_USERNAME
|
||||
value: user
|
||||
- name: RABBITMQ_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
key: rabbitmq-password
|
||||
name: oncall-rabbitmq
|
||||
- name: RABBITMQ_HOST
|
||||
value: oncall-rabbitmq
|
||||
- name: RABBITMQ_PORT
|
||||
value: "5672"
|
||||
- name: RABBITMQ_PROTOCOL
|
||||
value: amqp
|
||||
- name: RABBITMQ_VHOST
|
||||
value: ""
|
||||
image: grafana/oncall:v1.3.20
|
||||
imagePullPolicy: Always
|
||||
name: telegram-polling
|
||||
securityContext: {}
|
||||
|
|
@ -141,6 +141,77 @@ database.type=mysql -> should create initContainer for MySQL database (default):
|
|||
cpu: 100m
|
||||
memory: 128Mi
|
||||
securityContext: {}
|
||||
3: |
|
||||
- command:
|
||||
- sh
|
||||
- -c
|
||||
- until (python manage.py migrate --check); do echo Waiting for database migrations; sleep 2; done
|
||||
env:
|
||||
- name: BASE_URL
|
||||
value: https://example.com
|
||||
- name: SECRET_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
key: SECRET_KEY
|
||||
name: oncall
|
||||
- name: MIRAGE_SECRET_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
key: MIRAGE_SECRET_KEY
|
||||
name: oncall
|
||||
- name: MIRAGE_CIPHER_IV
|
||||
value: 1234567890abcdef
|
||||
- name: DJANGO_SETTINGS_MODULE
|
||||
value: settings.helm
|
||||
- name: AMIXR_DJANGO_ADMIN_PATH
|
||||
value: admin
|
||||
- name: OSS
|
||||
value: "True"
|
||||
- name: UWSGI_LISTEN
|
||||
value: "1024"
|
||||
- name: BROKER_TYPE
|
||||
value: rabbitmq
|
||||
- name: GRAFANA_API_URL
|
||||
value: http://oncall-grafana
|
||||
- name: MYSQL_HOST
|
||||
value: oncall-mariadb
|
||||
- name: MYSQL_PORT
|
||||
value: "3306"
|
||||
- name: MYSQL_DB_NAME
|
||||
value: oncall
|
||||
- name: MYSQL_USER
|
||||
value: root
|
||||
- name: MYSQL_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
key: mariadb-root-password
|
||||
name: oncall-mariadb
|
||||
- name: RABBITMQ_USERNAME
|
||||
value: user
|
||||
- name: RABBITMQ_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
key: rabbitmq-password
|
||||
name: oncall-rabbitmq
|
||||
- name: RABBITMQ_HOST
|
||||
value: oncall-rabbitmq
|
||||
- name: RABBITMQ_PORT
|
||||
value: "5672"
|
||||
- name: RABBITMQ_PROTOCOL
|
||||
value: amqp
|
||||
- name: RABBITMQ_VHOST
|
||||
value: ""
|
||||
image: grafana/oncall:v1.2.36
|
||||
imagePullPolicy: Always
|
||||
name: wait-for-db
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
securityContext: {}
|
||||
database.type=postgresql -> should create initContainer for PostgreSQL database:
|
||||
1: |
|
||||
- command:
|
||||
|
|
@ -288,3 +359,76 @@ database.type=postgresql -> should create initContainer for PostgreSQL database:
|
|||
cpu: 100m
|
||||
memory: 128Mi
|
||||
securityContext: {}
|
||||
3: |
|
||||
- command:
|
||||
- sh
|
||||
- -c
|
||||
- until (python manage.py migrate --check); do echo Waiting for database migrations; sleep 2; done
|
||||
env:
|
||||
- name: BASE_URL
|
||||
value: https://example.com
|
||||
- name: SECRET_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
key: SECRET_KEY
|
||||
name: oncall
|
||||
- name: MIRAGE_SECRET_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
key: MIRAGE_SECRET_KEY
|
||||
name: oncall
|
||||
- name: MIRAGE_CIPHER_IV
|
||||
value: 1234567890abcdef
|
||||
- name: DJANGO_SETTINGS_MODULE
|
||||
value: settings.helm
|
||||
- name: AMIXR_DJANGO_ADMIN_PATH
|
||||
value: admin
|
||||
- name: OSS
|
||||
value: "True"
|
||||
- name: UWSGI_LISTEN
|
||||
value: "1024"
|
||||
- name: BROKER_TYPE
|
||||
value: rabbitmq
|
||||
- name: GRAFANA_API_URL
|
||||
value: http://oncall-grafana
|
||||
- name: DATABASE_TYPE
|
||||
value: postgresql
|
||||
- name: DATABASE_HOST
|
||||
value: some-postgresql-host
|
||||
- name: DATABASE_PORT
|
||||
value: "5432"
|
||||
- name: DATABASE_NAME
|
||||
value: oncall
|
||||
- name: DATABASE_USER
|
||||
value: postgres
|
||||
- name: DATABASE_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
key: postgres-password
|
||||
name: oncall-postgresql-external
|
||||
- name: RABBITMQ_USERNAME
|
||||
value: user
|
||||
- name: RABBITMQ_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
key: rabbitmq-password
|
||||
name: oncall-rabbitmq
|
||||
- name: RABBITMQ_HOST
|
||||
value: oncall-rabbitmq
|
||||
- name: RABBITMQ_PORT
|
||||
value: "5672"
|
||||
- name: RABBITMQ_PROTOCOL
|
||||
value: amqp
|
||||
- name: RABBITMQ_VHOST
|
||||
value: ""
|
||||
image: grafana/oncall:v1.2.36
|
||||
imagePullPolicy: Always
|
||||
name: wait-for-db
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
securityContext: {}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,13 @@ templates:
|
|||
- engine/deployment.yaml
|
||||
- engine/job-migrate.yaml
|
||||
- celery/deployment.yaml
|
||||
- telegram-polling/deployment.yaml
|
||||
release:
|
||||
name: oncall
|
||||
tests:
|
||||
- it: env=[] -> should support old syntax
|
||||
set:
|
||||
telegramPolling.enabled: true
|
||||
env:
|
||||
- name: SOME_VAR
|
||||
value: some_value
|
||||
|
|
@ -20,6 +22,7 @@ tests:
|
|||
|
||||
- it: env=map[] -> should set multiple envs
|
||||
set:
|
||||
telegramPolling.enabled: true
|
||||
env:
|
||||
SOME_VAR: some_value
|
||||
another_var: "another_value"
|
||||
|
|
@ -39,7 +42,9 @@ tests:
|
|||
templates:
|
||||
- engine/deployment.yaml
|
||||
- celery/deployment.yaml
|
||||
- telegram-polling/deployment.yaml
|
||||
set:
|
||||
telegramPolling.enabled: true
|
||||
env:
|
||||
- name: SOME_VAR
|
||||
value: some_value
|
||||
|
|
@ -54,7 +59,9 @@ tests:
|
|||
templates:
|
||||
- engine/deployment.yaml
|
||||
- celery/deployment.yaml
|
||||
- telegram-polling/deployment.yaml
|
||||
set:
|
||||
telegramPolling.enabled: true
|
||||
env:
|
||||
SOME_VAR: some_value
|
||||
another_var: "another_value"
|
||||
|
|
@ -74,7 +81,9 @@ tests:
|
|||
templates:
|
||||
- engine/deployment.yaml
|
||||
- celery/deployment.yaml
|
||||
- telegram-polling/deployment.yaml
|
||||
set:
|
||||
telegramPolling.enabled: true
|
||||
database.type: postgresql
|
||||
postgresql.enabled: true
|
||||
env:
|
||||
|
|
@ -96,7 +105,9 @@ tests:
|
|||
templates:
|
||||
- engine/deployment.yaml
|
||||
- celery/deployment.yaml
|
||||
- telegram-polling/deployment.yaml
|
||||
set:
|
||||
telegramPolling.enabled: true
|
||||
database.type: postgresql
|
||||
postgresql.enabled: true
|
||||
env:
|
||||
|
|
|
|||
|
|
@ -3,12 +3,15 @@ templates:
|
|||
- celery/deployment.yaml
|
||||
- engine/deployment.yaml
|
||||
- engine/job-migrate.yaml
|
||||
- telegram-polling/deployment.yaml
|
||||
release:
|
||||
name: oncall
|
||||
chart:
|
||||
appVersion: 1.2.36
|
||||
tests:
|
||||
- it: image={} -> should use default image tag
|
||||
set:
|
||||
telegramPolling.enabled: true
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].image
|
||||
|
|
@ -19,6 +22,7 @@ tests:
|
|||
|
||||
- it: image.repository and image.tag -> should use custom image
|
||||
set:
|
||||
telegramPolling.enabled: true
|
||||
image:
|
||||
repository: custom-oncall
|
||||
tag: 1.2.36-custom
|
||||
|
|
|
|||
|
|
@ -3,12 +3,14 @@ templates:
|
|||
- celery/deployment.yaml
|
||||
- engine/deployment.yaml
|
||||
- engine/job-migrate.yaml
|
||||
- telegram-polling/deployment.yaml
|
||||
release:
|
||||
name: oncall
|
||||
tests:
|
||||
- it: imagePullSecrets=[] -> should not create spec.template.spec.imagePullSecrets
|
||||
set:
|
||||
imagePullSecrets: []
|
||||
telegramPolling.enabled: true
|
||||
asserts:
|
||||
- notExists:
|
||||
path: spec.template.spec.imagePullSecrets
|
||||
|
|
@ -17,6 +19,7 @@ tests:
|
|||
set:
|
||||
imagePullSecrets:
|
||||
- name: regcred
|
||||
telegramPolling.enabled: true
|
||||
asserts:
|
||||
- contains:
|
||||
path: spec.template.spec.imagePullSecrets
|
||||
|
|
|
|||
|
|
@ -3,11 +3,13 @@ templates:
|
|||
- engine/deployment.yaml
|
||||
- engine/job-migrate.yaml
|
||||
- celery/deployment.yaml
|
||||
- telegram-polling/deployment.yaml
|
||||
release:
|
||||
name: oncall
|
||||
tests:
|
||||
- it: mariadb.enabled=false -> external MySQL default settings
|
||||
set:
|
||||
telegramPolling.enabled: true
|
||||
mariadb.enabled: false
|
||||
asserts:
|
||||
- contains:
|
||||
|
|
@ -38,6 +40,7 @@ tests:
|
|||
|
||||
- it: externalMysql -> use external MySQL custom settings
|
||||
set:
|
||||
telegramPolling.enabled: true
|
||||
mariadb.enabled: false
|
||||
externalMysql:
|
||||
host: test-host
|
||||
|
|
@ -67,6 +70,8 @@ tests:
|
|||
value: test-host
|
||||
|
||||
- it: mariadb.enabled=true -> internal MySQL default settings
|
||||
set:
|
||||
telegramPolling.enabled: true
|
||||
asserts:
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
|
|
@ -91,6 +96,7 @@ tests:
|
|||
|
||||
- it: mariadb.auth -> internal MySQL custom settings
|
||||
set:
|
||||
telegramPolling.enabled: true
|
||||
mariadb:
|
||||
auth:
|
||||
database: grafana_oncall
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ templates:
|
|||
- engine/deployment.yaml
|
||||
- engine/job-migrate.yaml
|
||||
- celery/deployment.yaml
|
||||
- telegram-polling/deployment.yaml
|
||||
- secrets.yaml
|
||||
tests:
|
||||
- it: secrets -> should fail if externalMysql.password not set
|
||||
|
|
@ -20,7 +21,9 @@ tests:
|
|||
- engine/deployment.yaml
|
||||
- engine/job-migrate.yaml
|
||||
- celery/deployment.yaml
|
||||
- telegram-polling/deployment.yaml
|
||||
set:
|
||||
telegramPolling.enabled: true
|
||||
mariadb.enabled: false
|
||||
externalMysql:
|
||||
user: user123
|
||||
|
|
|
|||
|
|
@ -3,11 +3,13 @@ templates:
|
|||
- engine/deployment.yaml
|
||||
- engine/job-migrate.yaml
|
||||
- celery/deployment.yaml
|
||||
- telegram-polling/deployment.yaml
|
||||
release:
|
||||
name: oncall
|
||||
tests:
|
||||
- it: postgresql.enabled=false -> external PostgreSQL default settings
|
||||
set:
|
||||
telegramPolling.enabled: true
|
||||
database.type: postgresql
|
||||
postgresql.enabled: false
|
||||
externalPostgresql.host: custom-postgres-host
|
||||
|
|
@ -40,6 +42,7 @@ tests:
|
|||
|
||||
- it: externalPostgresql -> should use external PostgreSQL custom settings
|
||||
set:
|
||||
telegramPolling.enabled: true
|
||||
database.type: postgresql
|
||||
postgresql.enabled: false
|
||||
externalPostgresql:
|
||||
|
|
@ -76,6 +79,7 @@ tests:
|
|||
|
||||
- it: postgresql.enabled=true -> internal PostgreSQL default settings
|
||||
set:
|
||||
telegramPolling.enabled: true
|
||||
database.type: postgresql
|
||||
postgresql.enabled: true
|
||||
asserts:
|
||||
|
|
@ -107,6 +111,7 @@ tests:
|
|||
|
||||
- it: postgresql.auth -> should use internal PostgreSQL custom settings
|
||||
set:
|
||||
telegramPolling.enabled: true
|
||||
database.type: postgresql
|
||||
postgresql:
|
||||
enabled: true
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ templates:
|
|||
- engine/deployment.yaml
|
||||
- engine/job-migrate.yaml
|
||||
- celery/deployment.yaml
|
||||
- telegram-polling/deployment.yaml
|
||||
- secrets.yaml
|
||||
tests:
|
||||
- it: secrets -> should fail if externalPostgresql.password not set
|
||||
|
|
@ -23,7 +24,9 @@ tests:
|
|||
- engine/deployment.yaml
|
||||
- engine/job-migrate.yaml
|
||||
- celery/deployment.yaml
|
||||
- telegram-polling/deployment.yaml
|
||||
set:
|
||||
telegramPolling.enabled: true
|
||||
database.type: postgresql
|
||||
postgresql.enabled: false
|
||||
externalPostgresql:
|
||||
|
|
@ -55,7 +58,9 @@ tests:
|
|||
- engine/deployment.yaml
|
||||
- engine/job-migrate.yaml
|
||||
- celery/deployment.yaml
|
||||
- telegram-polling/deployment.yaml
|
||||
set:
|
||||
telegramPolling.enabled: true
|
||||
database.type: postgresql
|
||||
postgresql.enabled: false
|
||||
externalPostgresql:
|
||||
|
|
@ -77,7 +82,9 @@ tests:
|
|||
- engine/deployment.yaml
|
||||
- engine/job-migrate.yaml
|
||||
- celery/deployment.yaml
|
||||
- telegram-polling/deployment.yaml
|
||||
set:
|
||||
telegramPolling.enabled: true
|
||||
database.type: postgresql
|
||||
postgresql.enabled: false
|
||||
externalPostgresql:
|
||||
|
|
@ -99,7 +106,9 @@ tests:
|
|||
- engine/deployment.yaml
|
||||
- engine/job-migrate.yaml
|
||||
- celery/deployment.yaml
|
||||
- telegram-polling/deployment.yaml
|
||||
set:
|
||||
telegramPolling.enabled: true
|
||||
database.type: postgresql
|
||||
postgresql:
|
||||
enabled: true
|
||||
|
|
|
|||
|
|
@ -3,11 +3,13 @@ templates:
|
|||
- celery/deployment.yaml
|
||||
- engine/deployment.yaml
|
||||
- engine/job-migrate.yaml
|
||||
- telegram-polling/deployment.yaml
|
||||
release:
|
||||
name: oncall
|
||||
tests:
|
||||
- it: podSecurityContext={} -> spec.template.spec.securityContext is empty (default)
|
||||
set:
|
||||
telegramPolling.enabled: true
|
||||
asserts:
|
||||
- isNullOrEmpty:
|
||||
path: spec.template.spec.securityContext
|
||||
|
|
@ -16,6 +18,7 @@ tests:
|
|||
|
||||
- it: podSecurityContext.runAsNonRoot=true -> should fill securityContext
|
||||
set:
|
||||
telegramPolling.enabled: true
|
||||
podSecurityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
|
|
@ -28,6 +31,7 @@ tests:
|
|||
|
||||
- it: securityContext.runAsNonRoot=true -> should fill securityContext for container
|
||||
set:
|
||||
telegramPolling.enabled: true
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
|
|
|
|||
|
|
@ -3,10 +3,13 @@ templates:
|
|||
- celery/deployment.yaml
|
||||
- engine/deployment.yaml
|
||||
- engine/job-migrate.yaml
|
||||
- telegram-polling/deployment.yaml
|
||||
release:
|
||||
name: oncall
|
||||
tests:
|
||||
- it: serviceAccount.create=true -> should use created serviceAccount for deployments (default)
|
||||
set:
|
||||
telegramPolling.enabled: true
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.template.spec.serviceAccountName
|
||||
|
|
@ -14,6 +17,7 @@ tests:
|
|||
|
||||
- it: serviceAccount.create=false -> should use default serviceAccount for deployments
|
||||
set:
|
||||
telegramPolling.enabled: true
|
||||
serviceAccount.create: false
|
||||
asserts:
|
||||
- equal:
|
||||
|
|
@ -22,6 +26,7 @@ tests:
|
|||
|
||||
- it: serviceAccount.name=custom -> should use created custom serviceAccount for deployments
|
||||
set:
|
||||
telegramPolling.enabled: true
|
||||
serviceAccount.name: custom
|
||||
asserts:
|
||||
- equal:
|
||||
|
|
|
|||
|
|
@ -2,10 +2,14 @@ suite: test telegram envs for deployments
|
|||
templates:
|
||||
- engine/deployment.yaml
|
||||
- celery/deployment.yaml
|
||||
- telegram-polling/deployment.yaml
|
||||
release:
|
||||
name: oncall
|
||||
tests:
|
||||
- it: oncall.telegram.enabled=false -> Telegram integration disabled (default)
|
||||
templates:
|
||||
- engine/deployment.yaml
|
||||
- celery/deployment.yaml
|
||||
asserts:
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
|
|
@ -14,6 +18,9 @@ tests:
|
|||
value: "False"
|
||||
|
||||
- it: oncall.telegram.enabled=true -> should enable Telegram integration
|
||||
templates:
|
||||
- engine/deployment.yaml
|
||||
- celery/deployment.yaml
|
||||
set:
|
||||
oncall.telegram:
|
||||
enabled: true
|
||||
|
|
@ -37,6 +44,9 @@ tests:
|
|||
value: "abcd:123"
|
||||
|
||||
- it: oncall.telegram.existingSecret=some-secret -> should prefer existing secret over oncall.telegram.token
|
||||
templates:
|
||||
- engine/deployment.yaml
|
||||
- celery/deployment.yaml
|
||||
set:
|
||||
oncall.telegram:
|
||||
enabled: true
|
||||
|
|
@ -52,3 +62,18 @@ tests:
|
|||
secretKeyRef:
|
||||
name: some-secret
|
||||
key: token
|
||||
|
||||
- it: telegramPolling.enabled=true -> should enable oncall.telegram.enabled too
|
||||
set:
|
||||
telegramPolling.enabled: true
|
||||
asserts:
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: FEATURE_TELEGRAM_INTEGRATION_ENABLED
|
||||
value: "True"
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: FEATURE_TELEGRAM_LONG_POLLING_ENABLED
|
||||
value: "True"
|
||||
|
|
|
|||
73
helm/oncall/tests/telegram_polling_deployment_test.yaml
Normal file
73
helm/oncall/tests/telegram_polling_deployment_test.yaml
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
suite: test telegram polling deployment
|
||||
templates:
|
||||
- telegram-polling/deployment.yaml
|
||||
release:
|
||||
name: oncall
|
||||
tests:
|
||||
- it: telegramPolling.enabled=false -> should not create deployment (default)
|
||||
asserts:
|
||||
- hasDocuments:
|
||||
count: 0
|
||||
|
||||
- it: telegramPolling.enabled=true -> should create telegram polling deployment
|
||||
set:
|
||||
telegramPolling.enabled: true
|
||||
asserts:
|
||||
- containsDocument:
|
||||
kind: Deployment
|
||||
apiVersion: apps/v1
|
||||
name: oncall-telegram-polling
|
||||
- isSubset:
|
||||
path: metadata.labels
|
||||
content:
|
||||
app.kubernetes.io/component: telegram-polling
|
||||
app.kubernetes.io/instance: oncall
|
||||
app.kubernetes.io/name: oncall
|
||||
- isSubset:
|
||||
path: spec.selector.matchLabels
|
||||
content:
|
||||
app.kubernetes.io/component: telegram-polling
|
||||
app.kubernetes.io/instance: oncall
|
||||
app.kubernetes.io/name: oncall
|
||||
- isSubset:
|
||||
path: spec.template.metadata.labels
|
||||
content:
|
||||
app.kubernetes.io/component: telegram-polling
|
||||
app.kubernetes.io/instance: oncall
|
||||
app.kubernetes.io/name: oncall
|
||||
# Should contain only one replica to avoid Conflict while polling Telegram updates
|
||||
- equal:
|
||||
path: spec.replicas
|
||||
value: 1
|
||||
- equal:
|
||||
path: spec.template.spec.serviceAccountName
|
||||
value: oncall
|
||||
- contains:
|
||||
path: spec.template.spec.initContainers
|
||||
content:
|
||||
name: wait-for-db
|
||||
any: true
|
||||
- matchSnapshot:
|
||||
path: spec.template.spec.containers
|
||||
|
||||
- it: telegramPolling.resources -> should specify resources
|
||||
set:
|
||||
telegramPolling:
|
||||
enabled: true
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].resources
|
||||
value:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
|
|
@ -2,6 +2,7 @@ suite: test init container wait-for-db in deployments
|
|||
templates:
|
||||
- celery/deployment.yaml
|
||||
- engine/deployment.yaml
|
||||
- telegram-polling/deployment.yaml
|
||||
release:
|
||||
name: oncall
|
||||
chart:
|
||||
|
|
@ -16,6 +17,8 @@ tests:
|
|||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
telegramPolling.enabled: true
|
||||
database.type: mysql
|
||||
asserts:
|
||||
- contains:
|
||||
path: spec.template.spec.initContainers
|
||||
|
|
@ -32,6 +35,7 @@ tests:
|
|||
|
||||
- it: database.type=postgresql -> should create initContainer for PostgreSQL database
|
||||
set:
|
||||
telegramPolling.enabled: true
|
||||
database.type: postgresql
|
||||
externalPostgresql.host: some-postgresql-host
|
||||
init.resources:
|
||||
|
|
|
|||
|
|
@ -134,6 +134,17 @@ celery:
|
|||
# - --port=5432
|
||||
# - example:europe-west3:grafana-oncall-db
|
||||
|
||||
# Telegram polling pod configuration
|
||||
telegramPolling:
|
||||
enabled: false
|
||||
resources: {}
|
||||
# limits:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
# requests:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
|
||||
oncall:
|
||||
# this is intended to be used for local development. In short, it will mount the ./engine dir into
|
||||
# any backend related containers, to allow hot-reloading + also run the containers with slightly modified
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue