From edb892d54bbb30e37eac5d7bf16b86bd3058f23d Mon Sep 17 00:00:00 2001 From: Alexandr Cherepanov Date: Wed, 31 May 2023 12:13:34 +0600 Subject: [PATCH 01/17] Telegram long polling implementation instead of webhook --- engine/apps/api/views/live_setting.py | 5 ++++- engine/apps/base/models/live_setting.py | 2 ++ engine/apps/telegram/client.py | 7 ++++++ engine/apps/telegram/tasks.py | 30 +++++++++++++++++++++++++ engine/settings/base.py | 1 + engine/settings/prod_without_db.py | 1 + 6 files changed, 45 insertions(+), 1 deletion(-) diff --git a/engine/apps/api/views/live_setting.py b/engine/apps/api/views/live_setting.py index 760e3f0ddb..11b3958ef8 100644 --- a/engine/apps/api/views/live_setting.py +++ b/engine/apps/api/views/live_setting.py @@ -13,7 +13,7 @@ from apps.oss_installation.tasks import sync_users_with_cloud from apps.slack.tasks import unpopulate_slack_user_identities from apps.telegram.client import TelegramClient -from apps.telegram.tasks import register_telegram_webhook +from apps.telegram.tasks import register_telegram_webhook, start_telegram_polling from apps.user_management.models import User from common.api_helpers.mixins import PublicPrimaryKeyMixin @@ -66,6 +66,9 @@ def perform_destroy(self, instance): self._post_update_hook(name, old_value) def _post_update_hook(self, name, old_value): + if name == "TELEGRAM_LONG_POLLING_ENABLED": + start_telegram_polling.delay() + if name == "TELEGRAM_TOKEN": self._reset_telegram_integration(old_token=old_value) register_telegram_webhook.delay() diff --git a/engine/apps/base/models/live_setting.py b/engine/apps/base/models/live_setting.py index f5a6f8e79f..b75d58996f 100644 --- a/engine/apps/base/models/live_setting.py +++ b/engine/apps/base/models/live_setting.py @@ -50,6 +50,7 @@ class LiveSetting(models.Model): "TWILIO_VERIFY_SERVICE_SID", "TELEGRAM_TOKEN", "TELEGRAM_WEBHOOK_HOST", + "TELEGRAM_LONG_POLLING_ENABLED", "SLACK_CLIENT_OAUTH_ID", "SLACK_CLIENT_OAUTH_SECRET", "SLACK_SIGNING_SECRET", @@ -147,6 +148,7 @@ class LiveSetting(models.Model): "TELEGRAM_WEBHOOK_HOST": ( "Externally available URL for Telegram to make requests. Must use https and ports 80, 88, 443, 8443." ), + "TELEGRAM_LONG_POLLING_ENABLED": ("Enable Telegram long polling instead of webhook integration."), "SEND_ANONYMOUS_USAGE_STATS": ( "Grafana OnCall will send anonymous, but uniquely-identifiable usage analytics to Grafana Labs." " These statistics are sent to https://stats.grafana.org/. For more information on what's sent, look at the " diff --git a/engine/apps/telegram/client.py b/engine/apps/telegram/client.py index 33e700725f..21b1b7899e 100644 --- a/engine/apps/telegram/client.py +++ b/engine/apps/telegram/client.py @@ -46,6 +46,13 @@ def register_webhook(self, webhook_url: Optional[str] = None) -> None: 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 == "": + return + + self.api_client.delete_webhook() + def send_message( self, chat_id: Union[int, str], diff --git a/engine/apps/telegram/tasks.py b/engine/apps/telegram/tasks.py index 57b2b373f7..002fc65b62 100644 --- a/engine/apps/telegram/tasks.py +++ b/engine/apps/telegram/tasks.py @@ -5,6 +5,7 @@ from django.apps import apps from django.conf import settings from telegram import error +from telegram.ext import CallbackQueryHandler, Filters, MessageHandler, Updater from apps.alerts.models import Alert, AlertGroup from apps.base.models import UserNotificationPolicy @@ -37,6 +38,35 @@ def register_telegram_webhook(token=None): logger.warning(f"Tried to register Telegram webhook using token: {telegram_client.token}, got error: {e}") +@shared_dedicated_queue_retry_task( + autoretry_for=(Exception,), retry_backoff=True, max_retries=1 if settings.DEBUG else None +) +@handle_missing_token +def start_telegram_polling(token=None): + telegram_client = TelegramClient(token=token) + + telegram_client.delete_webhook() + + updater = Updater(token=telegram_client.token, use_context=True) + 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 handle_message(update, context): + logger.info(f"Update from Telegram: {update}") + from apps.telegram.updates.update_manager import UpdateManager + + UpdateManager.process_update(update) + # do something with the message, e.g. log it + # logger.info('Received message from chat %s: %s', chat_id, message) + + @shared_dedicated_queue_retry_task( bind=True, autoretry_for=(Exception,), retry_backoff=True, max_retries=1 if settings.DEBUG else None ) diff --git a/engine/settings/base.py b/engine/settings/base.py index 5b793d271e..106160b6d3 100644 --- a/engine/settings/base.py +++ b/engine/settings/base.py @@ -66,6 +66,7 @@ FEATURE_PROMETHEUS_EXPORTER_ENABLED = getenv_boolean("FEATURE_PROMETHEUS_EXPORTER_ENABLED", default=False) 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) +TELEGRAM_LONG_POLLING_ENABLED = getenv_boolean("TELEGRAM_LONG_POLLING_ENABLED", default=False) TWILIO_API_KEY_SID = os.environ.get("TWILIO_API_KEY_SID") TWILIO_API_KEY_SECRET = os.environ.get("TWILIO_API_KEY_SECRET") diff --git a/engine/settings/prod_without_db.py b/engine/settings/prod_without_db.py index 355e81d2b8..379a6bf184 100644 --- a/engine/settings/prod_without_db.py +++ b/engine/settings/prod_without_db.py @@ -150,6 +150,7 @@ def on_uwsgi_worker_exit(): "apps.telegram.tasks.register_telegram_webhook": {"queue": "telegram"}, "apps.telegram.tasks.send_link_to_channel_message_or_fallback_to_full_alert_group": {"queue": "telegram"}, "apps.telegram.tasks.send_log_and_actions_message": {"queue": "telegram"}, + "apps.telegram.tasks.start_telegram_polling": {"queue": "telegram"}, # WEBHOOK "apps.alerts.tasks.custom_button_result.custom_button_result": {"queue": "webhook"}, "apps.mobile_app.fcm_relay.fcm_relay_async": {"queue": "webhook"}, From 5e4cdc7e585478bdf6431cf62b48e61db585342c Mon Sep 17 00:00:00 2001 From: Alexandr Cherepanov Date: Tue, 6 Jun 2023 14:36:44 +0600 Subject: [PATCH 02/17] #561 handle conflict error with telegram long polling --- CHANGELOG.md | 1 + engine/apps/api/views/live_setting.py | 5 +---- engine/apps/base/models/live_setting.py | 2 -- engine/apps/base/utils.py | 4 ++++ engine/apps/telegram/tasks.py | 16 ++++++++++++++++ engine/engine/celery.py | 7 +++++-- 6 files changed, 27 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6fd2a9d1d..7fdf409f70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -208,6 +208,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Allow mobile app to consume "internal" schedules API endpoints by @joeyorlando ([#2109](https://github.com/grafana/oncall/pull/2109)) - Add inbound email address in integration API by @vadimkerr ([#2113](https://github.com/grafana/oncall/pull/2113)) +- Use Telegram polling protocol instead of a webhook if `TELEGRAM_LONG_POLLING_ENABLED` set to `True` by @alexintech ### Changed diff --git a/engine/apps/api/views/live_setting.py b/engine/apps/api/views/live_setting.py index 11b3958ef8..760e3f0ddb 100644 --- a/engine/apps/api/views/live_setting.py +++ b/engine/apps/api/views/live_setting.py @@ -13,7 +13,7 @@ from apps.oss_installation.tasks import sync_users_with_cloud from apps.slack.tasks import unpopulate_slack_user_identities from apps.telegram.client import TelegramClient -from apps.telegram.tasks import register_telegram_webhook, start_telegram_polling +from apps.telegram.tasks import register_telegram_webhook from apps.user_management.models import User from common.api_helpers.mixins import PublicPrimaryKeyMixin @@ -66,9 +66,6 @@ def perform_destroy(self, instance): self._post_update_hook(name, old_value) def _post_update_hook(self, name, old_value): - if name == "TELEGRAM_LONG_POLLING_ENABLED": - start_telegram_polling.delay() - if name == "TELEGRAM_TOKEN": self._reset_telegram_integration(old_token=old_value) register_telegram_webhook.delay() diff --git a/engine/apps/base/models/live_setting.py b/engine/apps/base/models/live_setting.py index b75d58996f..f5a6f8e79f 100644 --- a/engine/apps/base/models/live_setting.py +++ b/engine/apps/base/models/live_setting.py @@ -50,7 +50,6 @@ class LiveSetting(models.Model): "TWILIO_VERIFY_SERVICE_SID", "TELEGRAM_TOKEN", "TELEGRAM_WEBHOOK_HOST", - "TELEGRAM_LONG_POLLING_ENABLED", "SLACK_CLIENT_OAUTH_ID", "SLACK_CLIENT_OAUTH_SECRET", "SLACK_SIGNING_SECRET", @@ -148,7 +147,6 @@ class LiveSetting(models.Model): "TELEGRAM_WEBHOOK_HOST": ( "Externally available URL for Telegram to make requests. Must use https and ports 80, 88, 443, 8443." ), - "TELEGRAM_LONG_POLLING_ENABLED": ("Enable Telegram long polling instead of webhook integration."), "SEND_ANONYMOUS_USAGE_STATS": ( "Grafana OnCall will send anonymous, but uniquely-identifiable usage analytics to Grafana Labs." " These statistics are sent to https://stats.grafana.org/. For more information on what's sent, look at the " diff --git a/engine/apps/base/utils.py b/engine/apps/base/utils.py index 65c9551b0d..238992d944 100644 --- a/engine/apps/base/utils.py +++ b/engine/apps/base/utils.py @@ -4,6 +4,7 @@ import phonenumbers from django.apps import apps +from django.conf import settings from phonenumbers import NumberParseException from telegram import Bot from twilio.base.exceptions import TwilioException @@ -136,6 +137,9 @@ def _check_telegram_token(cls, telegram_token): @classmethod def _check_telegram_webhook_host(cls, telegram_webhook_host): + if settings.TELEGRAM_LONG_POLLING_ENABLED: + return + try: # avoid circular import from apps.telegram.client import TelegramClient diff --git a/engine/apps/telegram/tasks.py b/engine/apps/telegram/tasks.py index 002fc65b62..3ad7657be3 100644 --- a/engine/apps/telegram/tasks.py +++ b/engine/apps/telegram/tasks.py @@ -1,5 +1,6 @@ import logging +import telegram.error from celery import uuid as celery_uuid from celery.utils.log import get_task_logger from django.apps import apps @@ -30,6 +31,9 @@ ) @handle_missing_token def register_telegram_webhook(token=None): + if settings.TELEGRAM_LONG_POLLING_ENABLED: + return + telegram_client = TelegramClient(token=token) try: @@ -48,6 +52,10 @@ def start_telegram_polling(token=None): 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 @@ -58,6 +66,14 @@ def start_telegram_polling(token=None): updater.start_polling() +def error_handler(update, context): + try: + raise context.error + except telegram.error.Conflict as e: + # Handle conflict error here + logger.warning(f"Tried to start telegram long polling, but conflict exists, got error: {e}") + + def handle_message(update, context): logger.info(f"Update from Telegram: {update}") from apps.telegram.updates.update_manager import UpdateManager diff --git a/engine/engine/celery.py b/engine/engine/celery.py index c7ac45fa43..7d6ac8b9a8 100644 --- a/engine/engine/celery.py +++ b/engine/engine/celery.py @@ -55,9 +55,12 @@ def on_after_setup_logger(logger, **kwargs): @celery.signals.worker_ready.connect def on_worker_ready(*args, **kwargs): - from apps.telegram.tasks import register_telegram_webhook + from apps.telegram.tasks import register_telegram_webhook, start_telegram_polling - register_telegram_webhook.delay() + if settings.TELEGRAM_LONG_POLLING_ENABLED: + start_telegram_polling.delay() + else: + register_telegram_webhook.delay() if settings.OTEL_TRACING_ENABLED and settings.OTEL_EXPORTER_OTLP_ENDPOINT: From 396161341c7f5843628587c55aa4ccba98e4e5d5 Mon Sep 17 00:00:00 2001 From: Alexandr Cherepanov Date: Thu, 8 Jun 2023 11:14:24 +0600 Subject: [PATCH 03/17] #561 start telegram long polling as separate container --- Makefile | 1 + dev/.env.dev.example | 2 +- docker-compose-developer.yml | 16 ++++++ engine/apps/telegram/tasks.py | 43 ---------------- engine/engine/celery.py | 6 +-- .../commands/start_telegram_polling.py | 50 +++++++++++++++++++ 6 files changed, 70 insertions(+), 48 deletions(-) create mode 100644 engine/engine/management/commands/start_telegram_polling.py diff --git a/Makefile b/Makefile index 381038c549..32160f2dfe 100644 --- a/Makefile +++ b/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 diff --git a/dev/.env.dev.example b/dev/.env.dev.example index 07258b088d..39cae3c600 100644 --- a/dev/.env.dev.example +++ b/dev/.env.dev.example @@ -28,7 +28,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 diff --git a/docker-compose-developer.yml b/docker-compose-developer.yml index d985604b92..dd13982876 100644 --- a/docker-compose-developer.yml +++ b/docker-compose-developer.yml @@ -82,6 +82,22 @@ services: profiles: - engine + oncall_telegram_polling: + container_name: oncall_telegram_polling + labels: *oncall-labels + build: *oncall-build-args + restart: always + 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 diff --git a/engine/apps/telegram/tasks.py b/engine/apps/telegram/tasks.py index 3ad7657be3..ed6075d4ff 100644 --- a/engine/apps/telegram/tasks.py +++ b/engine/apps/telegram/tasks.py @@ -1,12 +1,10 @@ import logging -import telegram.error from celery import uuid as celery_uuid from celery.utils.log import get_task_logger from django.apps import apps from django.conf import settings from telegram import error -from telegram.ext import CallbackQueryHandler, Filters, MessageHandler, Updater from apps.alerts.models import Alert, AlertGroup from apps.base.models import UserNotificationPolicy @@ -42,47 +40,6 @@ def register_telegram_webhook(token=None): logger.warning(f"Tried to register Telegram webhook using token: {telegram_client.token}, got error: {e}") -@shared_dedicated_queue_retry_task( - autoretry_for=(Exception,), retry_backoff=True, max_retries=1 if settings.DEBUG else None -) -@handle_missing_token -def start_telegram_polling(token=None): - telegram_client = TelegramClient(token=token) - - 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: - # Handle conflict error here - logger.warning(f"Tried to start telegram long polling, but conflict exists, got error: {e}") - - -def handle_message(update, context): - logger.info(f"Update from Telegram: {update}") - from apps.telegram.updates.update_manager import UpdateManager - - UpdateManager.process_update(update) - # do something with the message, e.g. log it - # logger.info('Received message from chat %s: %s', chat_id, message) - - @shared_dedicated_queue_retry_task( bind=True, autoretry_for=(Exception,), retry_backoff=True, max_retries=1 if settings.DEBUG else None ) diff --git a/engine/engine/celery.py b/engine/engine/celery.py index 7d6ac8b9a8..af8f30bb16 100644 --- a/engine/engine/celery.py +++ b/engine/engine/celery.py @@ -55,11 +55,9 @@ def on_after_setup_logger(logger, **kwargs): @celery.signals.worker_ready.connect def on_worker_ready(*args, **kwargs): - from apps.telegram.tasks import register_telegram_webhook, start_telegram_polling + from apps.telegram.tasks import register_telegram_webhook - if settings.TELEGRAM_LONG_POLLING_ENABLED: - start_telegram_polling.delay() - else: + if not settings.TELEGRAM_LONG_POLLING_ENABLED: register_telegram_webhook.delay() diff --git a/engine/engine/management/commands/start_telegram_polling.py b/engine/engine/management/commands/start_telegram_polling.py new file mode 100644 index 0000000000..78f4f564dc --- /dev/null +++ b/engine/engine/management/commands/start_telegram_polling.py @@ -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 start 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() From 9d19871e28616113e881bccd3adefc3046e4493f Mon Sep 17 00:00:00 2001 From: Alexandr Cherepanov Date: Mon, 12 Jun 2023 18:40:00 +0600 Subject: [PATCH 04/17] Helm Chart: add deployment for telegram long polling --- helm/oncall/templates/_env.tpl | 9 +- .../templates/telegram-polling/_helpers.tpl | 22 +++ .../telegram-polling/deployment.yaml | 55 +++++++ ...telegram_polling_deployment_test.yaml.snap | 73 +++++++++ .../__snapshot__/wait_for_db_test.yaml.snap | 148 ++++++++++++++++++ helm/oncall/tests/extra_env_test.yaml | 11 ++ helm/oncall/tests/image_deployments_test.yaml | 4 + .../oncall/tests/image_pull_secrets_test.yaml | 3 + helm/oncall/tests/mysql_env_test.yaml | 6 + .../oncall/tests/mysql_password_env_test.yaml | 3 + helm/oncall/tests/postgres_env_test.yaml | 5 + .../tests/postgres_password_env_test.yaml | 9 ++ .../security_context_deployments_test.yaml | 4 + .../service_account_deployments_test.yaml | 5 + helm/oncall/tests/telegram_env_test.yaml | 24 +++ .../telegram_polling_deployment_test.yaml | 81 ++++++++++ helm/oncall/tests/wait_for_db_test.yaml | 5 + helm/oncall/values.yaml | 11 ++ 18 files changed, 477 insertions(+), 1 deletion(-) create mode 100644 helm/oncall/templates/telegram-polling/_helpers.tpl create mode 100644 helm/oncall/templates/telegram-polling/deployment.yaml create mode 100644 helm/oncall/tests/__snapshot__/telegram_polling_deployment_test.yaml.snap create mode 100644 helm/oncall/tests/telegram_polling_deployment_test.yaml diff --git a/helm/oncall/templates/_env.tpl b/helm/oncall/templates/_env.tpl index 3632789e08..a09fb6dc29 100644 --- a/helm/oncall/templates/_env.tpl +++ b/helm/oncall/templates/_env.tpl @@ -95,9 +95,16 @@ {{- end }} {{- define "snippet.oncall.telegram.env" -}} +{{- if .Values.telegramPolling.enabled -}} +{{- $_ := set .Values.oncall.telegram "enabled" true -}} +{{- end -}} +{{- if .Values.oncall.telegram.enabled -}} - name: FEATURE_TELEGRAM_INTEGRATION_ENABLED value: {{ .Values.oncall.telegram.enabled | toString | title | quote }} -{{- if .Values.oncall.telegram.enabled }} +{{- if .Values.telegramPolling.enabled }} +- name: 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 }} diff --git a/helm/oncall/templates/telegram-polling/_helpers.tpl b/helm/oncall/templates/telegram-polling/_helpers.tpl new file mode 100644 index 0000000000..d2053dc076 --- /dev/null +++ b/helm/oncall/templates/telegram-polling/_helpers.tpl @@ -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 }} diff --git a/helm/oncall/templates/telegram-polling/deployment.yaml b/helm/oncall/templates/telegram-polling/deployment.yaml new file mode 100644 index 0000000000..fd19f13fc5 --- /dev/null +++ b/helm/oncall/templates/telegram-polling/deployment.yaml @@ -0,0 +1,55 @@ +{{- 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: + {{- if eq .Values.database.type "mysql" }} + {{- include "oncall.mariadb.wait-for-db" . | indent 8 }} + {{- end }} + {{- if eq .Values.database.type "postgresql" }} + {{- include "oncall.postgresql.wait-for-db" . | indent 8 }} + {{- end }} + 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 }} + {{- if eq .Values.database.type "mysql" }} + {{- include "snippet.mysql.env" . | nindent 12 }} + {{- end }} + {{- if eq .Values.database.type "postgresql" }} + {{- include "snippet.postgresql.env" . | nindent 12 }} + {{- end }} + {{- include "snippet.rabbitmq.env" . | nindent 12 }} + {{- include "snippet.redis.env" . | nindent 12 }} + {{- include "oncall.extraEnvs" . | nindent 12 }} + {{- with .Values.telegramPolling.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} +{{- end -}} diff --git a/helm/oncall/tests/__snapshot__/telegram_polling_deployment_test.yaml.snap b/helm/oncall/tests/__snapshot__/telegram_polling_deployment_test.yaml.snap new file mode 100644 index 0000000000..228ce4eb22 --- /dev/null +++ b/helm/oncall/tests/__snapshot__/telegram_polling_deployment_test.yaml.snap @@ -0,0 +1,73 @@ +telegramPolling.enabled=true -> should create telegram polling deployment: + 1: | + - 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: TELEGRAM_LONG_POLLING_ENABLED + value: "True" + - name: TELEGRAM_WEBHOOK_HOST + value: "" + - 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: "" + - name: REDIS_HOST + value: oncall-redis-master + - name: REDIS_PORT + value: "6379" + - name: REDIS_PASSWORD + valueFrom: + secretKeyRef: + key: redis-password + name: oncall-redis diff --git a/helm/oncall/tests/__snapshot__/wait_for_db_test.yaml.snap b/helm/oncall/tests/__snapshot__/wait_for_db_test.yaml.snap index 7d764bdef1..98ac2d7286 100644 --- a/helm/oncall/tests/__snapshot__/wait_for_db_test.yaml.snap +++ b/helm/oncall/tests/__snapshot__/wait_for_db_test.yaml.snap @@ -145,6 +145,79 @@ database.type=mysql -> should create initContainer for MySQL database (default): imagePullPolicy: Always name: wait-for-db 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: "" + - name: REDIS_HOST + value: oncall-redis-master + - name: REDIS_PORT + value: "6379" + - name: REDIS_PASSWORD + valueFrom: + secretKeyRef: + key: redis-password + name: oncall-redis + image: grafana/oncall:v1.2.36 + imagePullPolicy: Always + name: wait-for-db + securityContext: {} database.type=postgresql -> should create initContainer for PostgreSQL database: 1: | - command: @@ -296,3 +369,78 @@ database.type=postgresql -> should create initContainer for PostgreSQL database: imagePullPolicy: Always name: wait-for-db 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: oncall-postgresql + - 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 + - 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: "" + - name: REDIS_HOST + value: oncall-redis-master + - name: REDIS_PORT + value: "6379" + - name: REDIS_PASSWORD + valueFrom: + secretKeyRef: + key: redis-password + name: oncall-redis + image: grafana/oncall:v1.2.36 + imagePullPolicy: Always + name: wait-for-db + securityContext: {} diff --git a/helm/oncall/tests/extra_env_test.yaml b/helm/oncall/tests/extra_env_test.yaml index 53c61c2570..2179bc641d 100644 --- a/helm/oncall/tests/extra_env_test.yaml +++ b/helm/oncall/tests/extra_env_test.yaml @@ -3,11 +3,13 @@ templates: - engine/deployment.yaml - engine/job-migrate.yaml - celery/deployment-celery.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-celery.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-celery.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-celery.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-celery.yaml + - telegram-polling/deployment.yaml set: + telegramPolling.enabled: true database.type: postgresql postgresql.enabled: true env: diff --git a/helm/oncall/tests/image_deployments_test.yaml b/helm/oncall/tests/image_deployments_test.yaml index 1418ae7cdc..a6d8dd7870 100644 --- a/helm/oncall/tests/image_deployments_test.yaml +++ b/helm/oncall/tests/image_deployments_test.yaml @@ -3,12 +3,15 @@ templates: - celery/deployment-celery.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 diff --git a/helm/oncall/tests/image_pull_secrets_test.yaml b/helm/oncall/tests/image_pull_secrets_test.yaml index e4ffd7cb78..19eea19cce 100644 --- a/helm/oncall/tests/image_pull_secrets_test.yaml +++ b/helm/oncall/tests/image_pull_secrets_test.yaml @@ -3,12 +3,14 @@ templates: - celery/deployment-celery.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 diff --git a/helm/oncall/tests/mysql_env_test.yaml b/helm/oncall/tests/mysql_env_test.yaml index b374adbe9f..69efd7bd96 100644 --- a/helm/oncall/tests/mysql_env_test.yaml +++ b/helm/oncall/tests/mysql_env_test.yaml @@ -3,11 +3,13 @@ templates: - engine/deployment.yaml - engine/job-migrate.yaml - celery/deployment-celery.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 diff --git a/helm/oncall/tests/mysql_password_env_test.yaml b/helm/oncall/tests/mysql_password_env_test.yaml index b2447817f5..0cd27283c6 100644 --- a/helm/oncall/tests/mysql_password_env_test.yaml +++ b/helm/oncall/tests/mysql_password_env_test.yaml @@ -5,6 +5,7 @@ templates: - engine/deployment.yaml - engine/job-migrate.yaml - celery/deployment-celery.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-celery.yaml + - telegram-polling/deployment.yaml set: + telegramPolling.enabled: true mariadb.enabled: false externalMysql: user: user123 diff --git a/helm/oncall/tests/postgres_env_test.yaml b/helm/oncall/tests/postgres_env_test.yaml index fc2a9ce2ec..c537a63f20 100644 --- a/helm/oncall/tests/postgres_env_test.yaml +++ b/helm/oncall/tests/postgres_env_test.yaml @@ -3,11 +3,13 @@ templates: - engine/deployment.yaml - engine/job-migrate.yaml - celery/deployment-celery.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 diff --git a/helm/oncall/tests/postgres_password_env_test.yaml b/helm/oncall/tests/postgres_password_env_test.yaml index e35b146532..8a2709b457 100644 --- a/helm/oncall/tests/postgres_password_env_test.yaml +++ b/helm/oncall/tests/postgres_password_env_test.yaml @@ -5,6 +5,7 @@ templates: - engine/deployment.yaml - engine/job-migrate.yaml - celery/deployment-celery.yaml + - telegram-polling/deployment.yaml - secrets.yaml tests: - it: secrets -> should fail if externalPostgresql.password not set @@ -22,7 +23,9 @@ tests: - engine/deployment.yaml - engine/job-migrate.yaml - celery/deployment-celery.yaml + - telegram-polling/deployment.yaml set: + telegramPolling.enabled: true database.type: postgresql postgresql.enabled: false externalPostgresql: @@ -54,7 +57,9 @@ tests: - engine/deployment.yaml - engine/job-migrate.yaml - celery/deployment-celery.yaml + - telegram-polling/deployment.yaml set: + telegramPolling.enabled: true database.type: postgresql postgresql.enabled: false externalPostgresql: @@ -76,7 +81,9 @@ tests: - engine/deployment.yaml - engine/job-migrate.yaml - celery/deployment-celery.yaml + - telegram-polling/deployment.yaml set: + telegramPolling.enabled: true database.type: postgresql postgresql.enabled: false externalPostgresql: @@ -98,7 +105,9 @@ tests: - engine/deployment.yaml - engine/job-migrate.yaml - celery/deployment-celery.yaml + - telegram-polling/deployment.yaml set: + telegramPolling.enabled: true database.type: postgresql postgresql: enabled: true diff --git a/helm/oncall/tests/security_context_deployments_test.yaml b/helm/oncall/tests/security_context_deployments_test.yaml index 9cf6db81b5..3235ad7f9b 100644 --- a/helm/oncall/tests/security_context_deployments_test.yaml +++ b/helm/oncall/tests/security_context_deployments_test.yaml @@ -3,11 +3,13 @@ templates: - celery/deployment-celery.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 diff --git a/helm/oncall/tests/service_account_deployments_test.yaml b/helm/oncall/tests/service_account_deployments_test.yaml index 9fbe93034c..92a8c9edda 100644 --- a/helm/oncall/tests/service_account_deployments_test.yaml +++ b/helm/oncall/tests/service_account_deployments_test.yaml @@ -3,10 +3,13 @@ templates: - celery/deployment-celery.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: diff --git a/helm/oncall/tests/telegram_env_test.yaml b/helm/oncall/tests/telegram_env_test.yaml index 7f954568df..acde1783f6 100644 --- a/helm/oncall/tests/telegram_env_test.yaml +++ b/helm/oncall/tests/telegram_env_test.yaml @@ -2,10 +2,14 @@ suite: test telegram envs for deployments templates: - engine/deployment.yaml - celery/deployment-celery.yaml + - telegram-polling/deployment.yaml release: name: oncall tests: - it: oncall.telegram.enabled=false -> Telegram integration disabled (default) + templates: + - engine/deployment.yaml + - celery/deployment-celery.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-celery.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-celery.yaml set: oncall.telegram: enabled: true @@ -53,3 +63,17 @@ tests: 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: TELEGRAM_LONG_POLLING_ENABLED + value: "True" diff --git a/helm/oncall/tests/telegram_polling_deployment_test.yaml b/helm/oncall/tests/telegram_polling_deployment_test.yaml new file mode 100644 index 0000000000..06ae8a245d --- /dev/null +++ b/helm/oncall/tests/telegram_polling_deployment_test.yaml @@ -0,0 +1,81 @@ +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 + - equal: + path: spec.template.spec.containers[0].name + value: telegram-polling + - equal: + path: spec.template.spec.containers[0].command + value: ['sh', '-c', 'python manage.py start_telegram_polling'] + - notExists: + path: spec.template.spec.containers[0].resources + - matchSnapshot: + path: spec.template.spec.containers[0].env + + - 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 diff --git a/helm/oncall/tests/wait_for_db_test.yaml b/helm/oncall/tests/wait_for_db_test.yaml index e43b1ef8cb..59811aa62e 100644 --- a/helm/oncall/tests/wait_for_db_test.yaml +++ b/helm/oncall/tests/wait_for_db_test.yaml @@ -2,12 +2,16 @@ suite: test init container wait-for-db in deployments templates: - celery/deployment-celery.yaml - engine/deployment.yaml + - telegram-polling/deployment.yaml release: name: oncall chart: appVersion: v1.2.36 tests: - it: database.type=mysql -> should create initContainer for MySQL database (default) + set: + telegramPolling.enabled: true + database.type: mysql asserts: - contains: path: spec.template.spec.initContainers @@ -24,6 +28,7 @@ tests: - it: database.type=postgresql -> should create initContainer for PostgreSQL database set: + telegramPolling.enabled: true database.type: postgresql externalPostgresql.host: some-postgresql-host asserts: diff --git a/helm/oncall/values.yaml b/helm/oncall/values.yaml index 079ae51f17..3fdadc95c0 100644 --- a/helm/oncall/values.yaml +++ b/helm/oncall/values.yaml @@ -95,6 +95,17 @@ celery: ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ tolerations: [] +# Telegram polling pod configuration +telegramPolling: + enabled: false + resources: {} + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + oncall: # Override default MIRAGE_CIPHER_IV (must be 16 bytes long) # For existing installation, this should not be changed. From 5abddac864343bedce613f1b66356edb6341020a Mon Sep 17 00:00:00 2001 From: Alexandr Cherepanov Date: Mon, 12 Jun 2023 18:46:01 +0600 Subject: [PATCH 05/17] remove task from celery --- engine/settings/prod_without_db.py | 1 - 1 file changed, 1 deletion(-) diff --git a/engine/settings/prod_without_db.py b/engine/settings/prod_without_db.py index 379a6bf184..355e81d2b8 100644 --- a/engine/settings/prod_without_db.py +++ b/engine/settings/prod_without_db.py @@ -150,7 +150,6 @@ def on_uwsgi_worker_exit(): "apps.telegram.tasks.register_telegram_webhook": {"queue": "telegram"}, "apps.telegram.tasks.send_link_to_channel_message_or_fallback_to_full_alert_group": {"queue": "telegram"}, "apps.telegram.tasks.send_log_and_actions_message": {"queue": "telegram"}, - "apps.telegram.tasks.start_telegram_polling": {"queue": "telegram"}, # WEBHOOK "apps.alerts.tasks.custom_button_result.custom_button_result": {"queue": "webhook"}, "apps.mobile_app.fcm_relay.fcm_relay_async": {"queue": "webhook"}, From 19e7beb68ae3b87f5bbb53e4005d5ffa51dc50e4 Mon Sep 17 00:00:00 2001 From: Alexandr Cherepanov Date: Thu, 15 Jun 2023 17:12:31 +0600 Subject: [PATCH 06/17] add test and small fix --- CHANGELOG.md | 3 +- engine/apps/api/tests/test_live_settings.py | 30 +++++++++++++++++++ engine/apps/telegram/client.py | 2 +- .../commands/start_telegram_polling.py | 2 +- 4 files changed, 34 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fdf409f70..168483ac33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -148,6 +148,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `locale` column to mobile app user settings table by @joeyorlando [#2131](https://github.com/grafana/oncall/pull/2131) - Update notification text for "You're going on call" push notifications to include information about the shift start and end times by @joeyorlando ([#2131](https://github.com/grafana/oncall/pull/2131)) +- Use Telegram polling protocol instead of a webhook if `TELEGRAM_LONG_POLLING_ENABLED` set to `True` by @alexintech + ([#2250](https://github.com/grafana/oncall/pull/2250)) ### Fixed @@ -208,7 +210,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Allow mobile app to consume "internal" schedules API endpoints by @joeyorlando ([#2109](https://github.com/grafana/oncall/pull/2109)) - Add inbound email address in integration API by @vadimkerr ([#2113](https://github.com/grafana/oncall/pull/2113)) -- Use Telegram polling protocol instead of a webhook if `TELEGRAM_LONG_POLLING_ENABLED` set to `True` by @alexintech ### Changed diff --git a/engine/apps/api/tests/test_live_settings.py b/engine/apps/api/tests/test_live_settings.py index dce8623677..2bcb0a49e8 100644 --- a/engine/apps/api/tests/test_live_settings.py +++ b/engine/apps/api/tests/test_live_settings.py @@ -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 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.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() diff --git a/engine/apps/telegram/client.py b/engine/apps/telegram/client.py index 21b1b7899e..8bd547b2f9 100644 --- a/engine/apps/telegram/client.py +++ b/engine/apps/telegram/client.py @@ -48,7 +48,7 @@ def register_webhook(self, webhook_url: Optional[str] = None) -> None: def delete_webhook(self): webhook_info = self.api_client.get_webhook_info() - if webhook_info == "": + if webhook_info.url == "": return self.api_client.delete_webhook() diff --git a/engine/engine/management/commands/start_telegram_polling.py b/engine/engine/management/commands/start_telegram_polling.py index 78f4f564dc..4d15b434ee 100644 --- a/engine/engine/management/commands/start_telegram_polling.py +++ b/engine/engine/management/commands/start_telegram_polling.py @@ -35,7 +35,7 @@ def error_handler(update, context): try: raise context.error except telegram.error.Conflict as e: - logger.warning(f"Tried to start telegram long polling, but conflict exists, got error: {e}") + logger.warning(f"Tried to getUpdates() using telegram long polling, but conflict exists, got error: {e}") def handle_message(update, context): From 1387beb56b61359d737715195bcf6cd8e52c8c4f Mon Sep 17 00:00:00 2001 From: Alexandr Cherepanov Date: Thu, 15 Jun 2023 18:37:31 +0600 Subject: [PATCH 07/17] add user directive for telegram_polling container --- dev/README.md | 1 + docker-compose-developer.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/dev/README.md b/dev/README.md index fd33bc4798..6c65ae1d2f 100644 --- a/dev/README.md +++ b/dev/README.md @@ -75,6 +75,7 @@ The possible profiles values are: - `rabbitmq` - `postgres` - `mysql` +- `telegram_polling` The default is `engine,oncall_ui,redis,grafana`. This runs: diff --git a/docker-compose-developer.yml b/docker-compose-developer.yml index dd13982876..a8235cf06a 100644 --- a/docker-compose-developer.yml +++ b/docker-compose-developer.yml @@ -87,6 +87,7 @@ services: 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 From d9f16809f858ca96964e212fb13a829592a68a86 Mon Sep 17 00:00:00 2001 From: Alexandr Cherepanov Date: Wed, 28 Jun 2023 14:19:49 +0600 Subject: [PATCH 08/17] fix helm chart --- helm/oncall/templates/_env.tpl | 2 +- .../__snapshot__/telegram_polling_deployment_test.yaml.snap | 2 +- helm/oncall/tests/__snapshot__/wait_for_db_test.yaml.snap | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/helm/oncall/templates/_env.tpl b/helm/oncall/templates/_env.tpl index a09fb6dc29..7454d6f546 100644 --- a/helm/oncall/templates/_env.tpl +++ b/helm/oncall/templates/_env.tpl @@ -98,9 +98,9 @@ {{- if .Values.telegramPolling.enabled -}} {{- $_ := set .Values.oncall.telegram "enabled" true -}} {{- end -}} -{{- if .Values.oncall.telegram.enabled -}} - name: FEATURE_TELEGRAM_INTEGRATION_ENABLED value: {{ .Values.oncall.telegram.enabled | toString | title | quote }} +{{- if .Values.oncall.telegram.enabled -}} {{- if .Values.telegramPolling.enabled }} - name: TELEGRAM_LONG_POLLING_ENABLED value: {{ .Values.telegramPolling.enabled | toString | title | quote }} diff --git a/helm/oncall/tests/__snapshot__/telegram_polling_deployment_test.yaml.snap b/helm/oncall/tests/__snapshot__/telegram_polling_deployment_test.yaml.snap index 228ce4eb22..3162332c88 100644 --- a/helm/oncall/tests/__snapshot__/telegram_polling_deployment_test.yaml.snap +++ b/helm/oncall/tests/__snapshot__/telegram_polling_deployment_test.yaml.snap @@ -31,7 +31,7 @@ telegramPolling.enabled=true -> should create telegram polling deployment: - name: TELEGRAM_LONG_POLLING_ENABLED value: "True" - name: TELEGRAM_WEBHOOK_HOST - value: "" + value: https://example.com - name: TELEGRAM_TOKEN value: "" - name: MYSQL_HOST diff --git a/helm/oncall/tests/__snapshot__/wait_for_db_test.yaml.snap b/helm/oncall/tests/__snapshot__/wait_for_db_test.yaml.snap index 98ac2d7286..e3950d2c59 100644 --- a/helm/oncall/tests/__snapshot__/wait_for_db_test.yaml.snap +++ b/helm/oncall/tests/__snapshot__/wait_for_db_test.yaml.snap @@ -404,7 +404,7 @@ database.type=postgresql -> should create initContainer for PostgreSQL database: - name: DATABASE_TYPE value: postgresql - name: DATABASE_HOST - value: oncall-postgresql + value: some-postgresql-host - name: DATABASE_PORT value: "5432" - name: DATABASE_NAME @@ -415,7 +415,7 @@ database.type=postgresql -> should create initContainer for PostgreSQL database: valueFrom: secretKeyRef: key: postgres-password - name: oncall-postgresql + name: oncall-postgresql-external - name: RABBITMQ_USERNAME value: user - name: RABBITMQ_PASSWORD From 1a49b77d3e2909bf35a27c87b38dca148fbff383 Mon Sep 17 00:00:00 2001 From: Alexandr Cherepanov Date: Wed, 28 Jun 2023 14:59:14 +0600 Subject: [PATCH 09/17] rename TELEGRAM_LONG_POLLING_ENABLED to FEATURE_TELEGRAM_LONG_POLLING_ENABLED --- CHANGELOG.md | 2 +- engine/apps/api/tests/test_live_settings.py | 6 +++--- engine/apps/base/utils.py | 2 +- engine/apps/telegram/tasks.py | 2 +- engine/engine/celery.py | 2 +- helm/oncall/templates/_env.tpl | 2 +- .../__snapshot__/telegram_polling_deployment_test.yaml.snap | 2 +- helm/oncall/tests/telegram_env_test.yaml | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 168483ac33..9c716031c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -148,7 +148,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `locale` column to mobile app user settings table by @joeyorlando [#2131](https://github.com/grafana/oncall/pull/2131) - Update notification text for "You're going on call" push notifications to include information about the shift start and end times by @joeyorlando ([#2131](https://github.com/grafana/oncall/pull/2131)) -- Use Telegram polling protocol instead of a webhook if `TELEGRAM_LONG_POLLING_ENABLED` set to `True` by @alexintech +- 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)) ### Fixed diff --git a/engine/apps/api/tests/test_live_settings.py b/engine/apps/api/tests/test_live_settings.py index 2bcb0a49e8..db069358df 100644 --- a/engine/apps/api/tests/test_live_settings.py +++ b/engine/apps/api/tests/test_live_settings.py @@ -170,12 +170,12 @@ def test_live_settings_telegram_set_webhook_not_called_if_long_polling_enabled( settings, ): """ - Check that when TELEGRAM_LONG_POLLING_ENABLED is true setting webhook with updating TELEGRAM_WEBHOOK_HOST live setting - does not evaluate. + 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.TELEGRAM_LONG_POLLING_ENABLED = True + settings.FEATURE_TELEGRAM_LONG_POLLING_ENABLED = True organization, user, token = make_organization_and_user_with_plugin_token() LiveSetting.populate_settings_if_needed() diff --git a/engine/apps/base/utils.py b/engine/apps/base/utils.py index 238992d944..4b4dd21281 100644 --- a/engine/apps/base/utils.py +++ b/engine/apps/base/utils.py @@ -137,7 +137,7 @@ def _check_telegram_token(cls, telegram_token): @classmethod def _check_telegram_webhook_host(cls, telegram_webhook_host): - if settings.TELEGRAM_LONG_POLLING_ENABLED: + if settings.FEATURE_TELEGRAM_LONG_POLLING_ENABLED: return try: diff --git a/engine/apps/telegram/tasks.py b/engine/apps/telegram/tasks.py index ed6075d4ff..e39979e129 100644 --- a/engine/apps/telegram/tasks.py +++ b/engine/apps/telegram/tasks.py @@ -29,7 +29,7 @@ ) @handle_missing_token def register_telegram_webhook(token=None): - if settings.TELEGRAM_LONG_POLLING_ENABLED: + if settings.FEATURE_TELEGRAM_LONG_POLLING_ENABLED: return telegram_client = TelegramClient(token=token) diff --git a/engine/engine/celery.py b/engine/engine/celery.py index af8f30bb16..393aea4851 100644 --- a/engine/engine/celery.py +++ b/engine/engine/celery.py @@ -57,7 +57,7 @@ def on_after_setup_logger(logger, **kwargs): def on_worker_ready(*args, **kwargs): from apps.telegram.tasks import register_telegram_webhook - if not settings.TELEGRAM_LONG_POLLING_ENABLED: + if not settings.FEATURE_TELEGRAM_LONG_POLLING_ENABLED: register_telegram_webhook.delay() diff --git a/helm/oncall/templates/_env.tpl b/helm/oncall/templates/_env.tpl index 7454d6f546..0305a7563b 100644 --- a/helm/oncall/templates/_env.tpl +++ b/helm/oncall/templates/_env.tpl @@ -102,7 +102,7 @@ value: {{ .Values.oncall.telegram.enabled | toString | title | quote }} {{- if .Values.oncall.telegram.enabled -}} {{- if .Values.telegramPolling.enabled }} -- name: TELEGRAM_LONG_POLLING_ENABLED +- name: FEATURE_TELEGRAM_LONG_POLLING_ENABLED value: {{ .Values.telegramPolling.enabled | toString | title | quote }} {{- end }} - name: TELEGRAM_WEBHOOK_HOST diff --git a/helm/oncall/tests/__snapshot__/telegram_polling_deployment_test.yaml.snap b/helm/oncall/tests/__snapshot__/telegram_polling_deployment_test.yaml.snap index 3162332c88..e63ced4e90 100644 --- a/helm/oncall/tests/__snapshot__/telegram_polling_deployment_test.yaml.snap +++ b/helm/oncall/tests/__snapshot__/telegram_polling_deployment_test.yaml.snap @@ -28,7 +28,7 @@ telegramPolling.enabled=true -> should create telegram polling deployment: value: http://oncall-grafana - name: FEATURE_TELEGRAM_INTEGRATION_ENABLED value: "True" - - name: TELEGRAM_LONG_POLLING_ENABLED + - name: FEATURE_TELEGRAM_LONG_POLLING_ENABLED value: "True" - name: TELEGRAM_WEBHOOK_HOST value: https://example.com diff --git a/helm/oncall/tests/telegram_env_test.yaml b/helm/oncall/tests/telegram_env_test.yaml index acde1783f6..4c6b0edade 100644 --- a/helm/oncall/tests/telegram_env_test.yaml +++ b/helm/oncall/tests/telegram_env_test.yaml @@ -75,5 +75,5 @@ tests: - contains: path: spec.template.spec.containers[0].env content: - name: TELEGRAM_LONG_POLLING_ENABLED + name: FEATURE_TELEGRAM_LONG_POLLING_ENABLED value: "True" From 8ebcd7d953e4dd10f5cf9f06fa38cb354144dcae Mon Sep 17 00:00:00 2001 From: Alexandr Cherepanov Date: Wed, 28 Jun 2023 16:13:22 +0600 Subject: [PATCH 10/17] update changelog --- CHANGELOG.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c716031c0..0b842ded00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Added + +- 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)) + ## v1.3.8 (2023-07-11) ### Added @@ -148,8 +155,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `locale` column to mobile app user settings table by @joeyorlando [#2131](https://github.com/grafana/oncall/pull/2131) - Update notification text for "You're going on call" push notifications to include information about the shift start and end times by @joeyorlando ([#2131](https://github.com/grafana/oncall/pull/2131)) -- 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)) ### Fixed From 9a930ebfea64a07a83b56debf7eefea4cf424dec Mon Sep 17 00:00:00 2001 From: Alexandr Cherepanov Date: Wed, 28 Jun 2023 16:16:46 +0600 Subject: [PATCH 11/17] small change in helm chart --- helm/oncall/templates/_env.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helm/oncall/templates/_env.tpl b/helm/oncall/templates/_env.tpl index 0305a7563b..a651204112 100644 --- a/helm/oncall/templates/_env.tpl +++ b/helm/oncall/templates/_env.tpl @@ -100,7 +100,7 @@ {{- end -}} - name: FEATURE_TELEGRAM_INTEGRATION_ENABLED value: {{ .Values.oncall.telegram.enabled | toString | title | quote }} -{{- if .Values.oncall.telegram.enabled -}} +{{- if .Values.oncall.telegram.enabled }} {{- if .Values.telegramPolling.enabled }} - name: FEATURE_TELEGRAM_LONG_POLLING_ENABLED value: {{ .Values.telegramPolling.enabled | toString | title | quote }} From 7d68255904d8903dd92445378cebb78386d12879 Mon Sep 17 00:00:00 2001 From: Alexandr Cherepanov Date: Thu, 17 Aug 2023 16:36:32 +0600 Subject: [PATCH 12/17] fix: helm unit tests --- .../tests/__snapshot__/wait_for_db_test.yaml.snap | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/helm/oncall/tests/__snapshot__/wait_for_db_test.yaml.snap b/helm/oncall/tests/__snapshot__/wait_for_db_test.yaml.snap index 6835b1eb1a..b6874c91ce 100644 --- a/helm/oncall/tests/__snapshot__/wait_for_db_test.yaml.snap +++ b/helm/oncall/tests/__snapshot__/wait_for_db_test.yaml.snap @@ -231,6 +231,13 @@ database.type=mysql -> should create initContainer for MySQL database (default): 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: | @@ -471,4 +478,11 @@ database.type=postgresql -> should create initContainer for PostgreSQL database: image: grafana/oncall:v1.2.36 imagePullPolicy: Always name: wait-for-db + resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 100m + memory: 128Mi securityContext: {} From 9d0231545f5a2a61fbf78e84357d90c22a275d2b Mon Sep 17 00:00:00 2001 From: Alexandr Cherepanov Date: Thu, 17 Aug 2023 18:12:46 +0600 Subject: [PATCH 13/17] update documentation --- docs/sources/open-source/_index.md | 10 ++++++---- helm/oncall/README.md | 9 ++++++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/docs/sources/open-source/_index.md b/docs/sources/open-source/_index.md index c42b817435..011b30583f 100644 --- a/docs/sources/open-source/_index.md +++ b/docs/sources/open-source/_index.md @@ -178,18 +178,20 @@ frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media web-share" allowfullscreen> 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. diff --git a/helm/oncall/README.md b/helm/oncall/README.md index e55bc6faed..a4eaa782d7 100644 --- a/helm/oncall/README.md +++ b/helm/oncall/README.md @@ -214,7 +214,7 @@ oncall: `oncall.slack.commandName` is used for changing default bot slash command, `oncall`. In slack, it could be called via `/`. -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. From 23ebf38fe20cd0440ffb0bfda4df2e71a5f7c3b6 Mon Sep 17 00:00:00 2001 From: Alexandr Cherepanov Date: Fri, 18 Aug 2023 12:29:52 +0600 Subject: [PATCH 14/17] fix feature flag name --- engine/settings/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/settings/base.py b/engine/settings/base.py index 388a114ed4..ed90c1531a 100644 --- a/engine/settings/base.py +++ b/engine/settings/base.py @@ -59,6 +59,7 @@ # 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) @@ -67,7 +68,6 @@ FEATURE_GRAFANA_ALERTING_V2_ENABLED = getenv_boolean("FEATURE_GRAFANA_ALERTING_V2_ENABLED", default=False) 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) -TELEGRAM_LONG_POLLING_ENABLED = getenv_boolean("TELEGRAM_LONG_POLLING_ENABLED", default=False) TWILIO_API_KEY_SID = os.environ.get("TWILIO_API_KEY_SID") TWILIO_API_KEY_SECRET = os.environ.get("TWILIO_API_KEY_SECRET") From ebeec0548c50cf566369f4ded53b993644153110 Mon Sep 17 00:00:00 2001 From: Alexandr Cherepanov Date: Thu, 24 Aug 2023 11:00:16 +0600 Subject: [PATCH 15/17] fix telegram polling deployment and unit tests --- .../templates/telegram-polling/deployment.yaml | 17 +++-------------- .../telegram_polling_deployment_test.yaml.snap | 9 --------- .../__snapshot__/wait_for_db_test.yaml.snap | 18 ------------------ helm/oncall/tests/telegram_env_test.yaml | 6 +++--- 4 files changed, 6 insertions(+), 44 deletions(-) diff --git a/helm/oncall/templates/telegram-polling/deployment.yaml b/helm/oncall/templates/telegram-polling/deployment.yaml index fd19f13fc5..081599afc2 100644 --- a/helm/oncall/templates/telegram-polling/deployment.yaml +++ b/helm/oncall/templates/telegram-polling/deployment.yaml @@ -23,12 +23,7 @@ spec: securityContext: {{- toYaml .Values.podSecurityContext | nindent 8 }} initContainers: - {{- if eq .Values.database.type "mysql" }} - {{- include "oncall.mariadb.wait-for-db" . | indent 8 }} - {{- end }} - {{- if eq .Values.database.type "postgresql" }} - {{- include "oncall.postgresql.wait-for-db" . | indent 8 }} - {{- end }} + {{- include "oncall.initContainer" . | nindent 8 }} containers: - name: telegram-polling securityContext: @@ -39,14 +34,8 @@ spec: env: {{- include "snippet.oncall.env" . | nindent 12 }} {{- include "snippet.oncall.telegram.env" . | nindent 12 }} - {{- if eq .Values.database.type "mysql" }} - {{- include "snippet.mysql.env" . | nindent 12 }} - {{- end }} - {{- if eq .Values.database.type "postgresql" }} - {{- include "snippet.postgresql.env" . | nindent 12 }} - {{- end }} - {{- include "snippet.rabbitmq.env" . | nindent 12 }} - {{- include "snippet.redis.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: diff --git a/helm/oncall/tests/__snapshot__/telegram_polling_deployment_test.yaml.snap b/helm/oncall/tests/__snapshot__/telegram_polling_deployment_test.yaml.snap index e63ced4e90..ad49995c3b 100644 --- a/helm/oncall/tests/__snapshot__/telegram_polling_deployment_test.yaml.snap +++ b/helm/oncall/tests/__snapshot__/telegram_polling_deployment_test.yaml.snap @@ -62,12 +62,3 @@ telegramPolling.enabled=true -> should create telegram polling deployment: value: amqp - name: RABBITMQ_VHOST value: "" - - name: REDIS_HOST - value: oncall-redis-master - - name: REDIS_PORT - value: "6379" - - name: REDIS_PASSWORD - valueFrom: - secretKeyRef: - key: redis-password - name: oncall-redis diff --git a/helm/oncall/tests/__snapshot__/wait_for_db_test.yaml.snap b/helm/oncall/tests/__snapshot__/wait_for_db_test.yaml.snap index 158d6151a2..8a4586aac7 100644 --- a/helm/oncall/tests/__snapshot__/wait_for_db_test.yaml.snap +++ b/helm/oncall/tests/__snapshot__/wait_for_db_test.yaml.snap @@ -201,15 +201,6 @@ database.type=mysql -> should create initContainer for MySQL database (default): value: amqp - name: RABBITMQ_VHOST value: "" - - name: REDIS_HOST - value: oncall-redis-master - - name: REDIS_PORT - value: "6379" - - name: REDIS_PASSWORD - valueFrom: - secretKeyRef: - key: redis-password - name: oncall-redis image: grafana/oncall:v1.2.36 imagePullPolicy: Always name: wait-for-db @@ -430,15 +421,6 @@ database.type=postgresql -> should create initContainer for PostgreSQL database: value: amqp - name: RABBITMQ_VHOST value: "" - - name: REDIS_HOST - value: oncall-redis-master - - name: REDIS_PORT - value: "6379" - - name: REDIS_PASSWORD - valueFrom: - secretKeyRef: - key: redis-password - name: oncall-redis image: grafana/oncall:v1.2.36 imagePullPolicy: Always name: wait-for-db diff --git a/helm/oncall/tests/telegram_env_test.yaml b/helm/oncall/tests/telegram_env_test.yaml index bfbef50dd9..288d5ee65a 100644 --- a/helm/oncall/tests/telegram_env_test.yaml +++ b/helm/oncall/tests/telegram_env_test.yaml @@ -9,7 +9,7 @@ tests: - it: oncall.telegram.enabled=false -> Telegram integration disabled (default) templates: - engine/deployment.yaml - - celery/deployment-celery.yaml + - celery/deployment.yaml asserts: - contains: path: spec.template.spec.containers[0].env @@ -20,7 +20,7 @@ tests: - it: oncall.telegram.enabled=true -> should enable Telegram integration templates: - engine/deployment.yaml - - celery/deployment-celery.yaml + - celery/deployment.yaml set: oncall.telegram: enabled: true @@ -46,7 +46,7 @@ tests: - it: oncall.telegram.existingSecret=some-secret -> should prefer existing secret over oncall.telegram.token templates: - engine/deployment.yaml - - celery/deployment-celery.yaml + - celery/deployment.yaml set: oncall.telegram: enabled: true From 5ab2f089ec793870b845eb12d71556423aca113d Mon Sep 17 00:00:00 2001 From: Alexandr Cherepanov Date: Thu, 24 Aug 2023 11:23:30 +0600 Subject: [PATCH 16/17] revert mistaken changes --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11fcbe04eb..3ea0a19749 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -275,6 +275,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Modified DRF pagination class used by `GET /api/internal/v1/alert_receive_channels` and `GET /api/internal/v1/schedules` endpoints so that the `next` and `previous` pagination links are properly set when OnCall is run behind a reverse proxy by @joeyorlando ([#2467](https://github.com/grafana/oncall/pull/2467)) +- Polish user settings and warnings ([#2425](https://github.com/grafana/oncall/pull/2425)) ### Fixed @@ -312,7 +313,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - UI drawer updates for webhooks2 ([#2419](https://github.com/grafana/oncall/pull/2419)) -- Removed url from sms notification, changed format ([2317](https://github.com/grafana/oncall/pull/2317)) +- Removed url from sms notification, changed format ([#2317](https://github.com/grafana/oncall/pull/2317)) ## v1.3.3 (2023-06-29) From 79059ec9b71c8f816614b485963ec914248bd59f Mon Sep 17 00:00:00 2001 From: Alexandr Cherepanov Date: Thu, 24 Aug 2023 11:44:59 +0600 Subject: [PATCH 17/17] small updates to telegram polling deployment tests --- ...telegram_polling_deployment_test.yaml.snap | 133 ++++++++++-------- .../telegram_polling_deployment_test.yaml | 10 +- 2 files changed, 72 insertions(+), 71 deletions(-) diff --git a/helm/oncall/tests/__snapshot__/telegram_polling_deployment_test.yaml.snap b/helm/oncall/tests/__snapshot__/telegram_polling_deployment_test.yaml.snap index ad49995c3b..18e4e440a0 100644 --- a/helm/oncall/tests/__snapshot__/telegram_polling_deployment_test.yaml.snap +++ b/helm/oncall/tests/__snapshot__/telegram_polling_deployment_test.yaml.snap @@ -1,64 +1,73 @@ telegramPolling.enabled=true -> should create telegram polling deployment: 1: | - - 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: "" + - 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: {} diff --git a/helm/oncall/tests/telegram_polling_deployment_test.yaml b/helm/oncall/tests/telegram_polling_deployment_test.yaml index 06ae8a245d..96fb8d0131 100644 --- a/helm/oncall/tests/telegram_polling_deployment_test.yaml +++ b/helm/oncall/tests/telegram_polling_deployment_test.yaml @@ -47,16 +47,8 @@ tests: content: name: wait-for-db any: true - - equal: - path: spec.template.spec.containers[0].name - value: telegram-polling - - equal: - path: spec.template.spec.containers[0].command - value: ['sh', '-c', 'python manage.py start_telegram_polling'] - - notExists: - path: spec.template.spec.containers[0].resources - matchSnapshot: - path: spec.template.spec.containers[0].env + path: spec.template.spec.containers - it: telegramPolling.resources -> should specify resources set: