Skip to content

Commit

Permalink
[back][infra] refactor: add write_on_discord command (#979)
Browse files Browse the repository at this point in the history
Co-authored-by: Adrien Matissart <a@matissart.net>
Co-authored-by: Gresille&Siffle <39056254+GresilleSiffle@users.noreply.github.com>
  • Loading branch information
3 people authored Sep 6, 2022
1 parent b17d558 commit 9f88d2f
Show file tree
Hide file tree
Showing 31 changed files with 123 additions and 122 deletions.
Empty file added backend/core/lib/__init__.py
Empty file.
18 changes: 18 additions & 0 deletions backend/core/lib/discord/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import logging

import requests
from django.conf import settings


def write_in_channel(discord_channel, message) -> bool:
"""Write a message in a Discord channel."""
webhook_url = settings.DISCORD_CHANNEL_WEBHOOKS.get(discord_channel, "")

if not webhook_url:
logging.warning("Cannot write in discord channel %s", discord_channel)
logging.warning("Cause: empty webhook URL.")
return False

resp = requests.post(webhook_url, json={"content": message})
resp.raise_for_status()
return True
42 changes: 42 additions & 0 deletions backend/core/management/commands/send_on_discord.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""
Send a message to a configured Discord channel.
The web hook of the target channel must be configured in the settings.
"""

from django.core.management.base import BaseCommand

from core.lib.discord.api import write_in_channel


class Command(BaseCommand):
help = "Send a message to a configured Discord channel."

def add_arguments(self, parser):

parser.add_argument(
"-c",
"--channel",
type=str,
help="Name of the target channel.",
)

parser.add_argument(
"-m",
"--message",
type=str,
help="Message to send.",
)

def handle(self, *args, **options):
self.stdout.write(f"start command: {__name__}")
discord_channel = options["channel"]

# display the configuration if more verbosity is asked
if options.get("verbosity", 1) > 1:
self.stdout.write(f"Discord channel: {discord_channel}")

write_in_channel(discord_channel, options["message"])

self.stdout.write(self.style.SUCCESS(f"Message posted on {discord_channel}"))
self.stdout.write("end")
2 changes: 2 additions & 0 deletions backend/settings/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,8 @@
YOUTUBE_API_KEY = server_settings.get("YOUTUBE_API_KEY", "")
ENABLE_API_WIKIDATA = server_settings.get("ENABLE_API_WIKIDATA", {"MIGRATIONS": False})

DISCORD_CHANNEL_WEBHOOKS = server_settings.get("DISCORD_CHANNEL_WEBHOOKS", {})

TWITTERBOT_CREDENTIALS = server_settings.get("TWITTERBOT_CREDENTIALS", {})

LOGGING = {
Expand Down
4 changes: 4 additions & 0 deletions backend/twitterbot/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,7 @@
"tournesol.app/entities/yt:{video_id}"
),
}

# Name of the Discord channel where the twitterbot will post its tweets.
# An empty value won't trigger any post.
TWITTERBOT_DISCORD_CHANNEL = "twitter"
17 changes: 15 additions & 2 deletions backend/twitterbot/tournesolbot.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import random
import re

from core.lib.discord.api import write_in_channel
from core.utils.time import time_ago
from tournesol.models import Entity
from tournesol.models.criteria import CriteriaLocale
Expand Down Expand Up @@ -46,7 +47,9 @@ def prepare_tweet(video):
# Get two best criteria and criteria dict name
crit1, crit2 = get_best_criteria(video, 2)
crit_dict = dict(
CriteriaLocale.objects.filter(language=language).values_list("criteria__name", "label")
CriteriaLocale.objects.filter(language=language).values_list(
"criteria__name", "label"
)
)

# Replace "@" by a smaller "@" to avoid false mentions in the tweet
Expand Down Expand Up @@ -99,7 +102,9 @@ def get_video_recommendations(language):
# Filter videos with some quality criteria
tweetable_videos = Entity.objects.filter(
add_time__lte=time_ago(days=settings.DAYS_TOO_RECENT),
metadata__publication_date__gte=time_ago(days=settings.DAYS_TOO_OLD).isoformat(),
metadata__publication_date__gte=time_ago(
days=settings.DAYS_TOO_OLD
).isoformat(),
rating_n_contributors__gt=settings.MIN_NB_CONTRIBUTORS,
rating_n_ratings__gte=settings.MIN_NB_RATINGS,
metadata__language=language,
Expand Down Expand Up @@ -160,6 +165,14 @@ def tweet_video_recommendation(bot_name, assumeyes=False):
# Tweet the video
resp = twitterbot.api.update_status(tweet_text)

# Post the tweet on Discord
discord_channel = settings.TWITTERBOT_DISCORD_CHANNEL
if discord_channel:
write_in_channel(
discord_channel,
f"https://twitter.com/{bot_name}/status/{resp.id}",
)

# Add the video to the TweetInfo table
TweetInfo.objects.create(
video=video,
Expand Down
7 changes: 0 additions & 7 deletions infra/ansible/roles/backups/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,6 @@
src: aws_secret_access_key.j2
when: export_backups_bucket_name is defined and export_backups_bucket_name != ""

- name: Copy Discord backups export failure alert
template:
dest: /usr/local/bin/discord-export-backups-fail-alert.sh
src: discord-export-backups-fail-alert.sh.j2
mode: a=rx
when: export_backups_bucket_name is defined and export_backups_bucket_name != ""

- name: Copy backups export service
template:
dest: /etc/systemd/system/export-backups.service
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ ExecStart=aws s3 sync /backups s3://{{export_backups_bucket_name}}/{{export_back
{% else %}
ExecStart=echo "would export backups but no bucket provided"
{% endif %}
ExecStopPost=/usr/bin/bash -c "if [ "$$EXIT_STATUS" != 0 ]; then /usr/local/bin/discord-export-backups-fail-alert.sh; fi"
ExecStopPost=/usr/bin/bash -c "if [ "$$EXIT_STATUS" != 0 ]; then /usr/local/bin/post-on-discord.sh -c infra_alert -m 'Backups export failed for {{domain_name}}'; fi"
4 changes: 2 additions & 2 deletions infra/ansible/roles/django/handlers/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@

- name: Notify backend upgrade
shell:
cmd: "wget -qO /dev/null --post-data='{\"content\": \"**{{domain_name}}** - new back end deployed: {{git_reference}}\"}' --header='Content-Type:application/json' '{{discord_alerting_webhook}}?wait=true'"
cmd: "wget -qO /dev/null --post-data='{\"content\": \"**{{domain_name}}** - new back end deployed: {{git_reference}}\"}' --header='Content-Type:application/json' '{{discord_infra_alert_webhook}}?wait=true'"
executable: /usr/bin/bash
when: discord_alerting_webhook is defined and discord_alerting_webhook != ""
when: discord_infra_alert_webhook is defined and discord_infra_alert_webhook != ""

- name: Collect Django static assets
shell:
Expand Down
28 changes: 6 additions & 22 deletions infra/ansible/roles/django/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -157,11 +157,13 @@

- meta: flush_handlers

- name: Copy Discord ML training failure alert
- name: Copy Post on Discord
template:
dest: /usr/local/bin/discord-ml-fail-alert.sh
src: discord-ml-fail-alert.sh.j2
mode: a=rx
dest: /usr/local/bin/post-on-discord.sh
src: post-on-discord.sh.j2
owner: gunicorn
group: gunicorn
mode: u=rx

- name: Copy ML training service
template:
Expand Down Expand Up @@ -192,12 +194,6 @@

# scheduled task: refresh token clean-up

- name: Copy Discord Tournesol API cleartokens failure alert
template:
dest: /usr/local/bin/discord-tournesolapi-cleartokens-fail-alert.sh
src: discord-tournesolapi-cleartokens-fail-alert.sh.j2
mode: a=rx

- name: Copy Tournesol API cleartokens service
template:
dest: /etc/systemd/system/tournesol-api-cleartokens.service
Expand All @@ -217,12 +213,6 @@

# scheduled task: inactive users clean-up

- name: Copy Discord Tournesol API delete-inactive-users failure alert
template:
dest: /usr/local/bin/discord-tournesolapi-deleteinactiveusers-fail-alert.sh
src: discord-tournesolapi-deleteinactiveusers-fail-alert.sh.j2
mode: a=rx

- name: Copy Tournesol API delete-inactive-users service
template:
dest: /etc/systemd/system/tournesol-api-delete-inactive-users.service
Expand All @@ -242,12 +232,6 @@

# scheduled task: Twitterbot

- name: Copy twitterbot failure alert script
template:
dest: /usr/local/bin/discord-twitterbot-fail-alert.sh
src: discord-twitterbot-fail-alert.sh.j2
mode: a=rx

- name: Copy twitterbot service
template:
dest: /etc/systemd/system/tournesol-twitterbot.service
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

2 changes: 1 addition & 1 deletion infra/ansible/roles/django/templates/ml-train.service.j2
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ Group=gunicorn
WorkingDirectory=/srv/tournesol-backend
Environment="SETTINGS_FILE=/etc/tournesol/settings.yaml"
ExecStart=/usr/bin/bash -c "source venv/bin/activate && python manage.py ml_train"
ExecStopPost=/usr/bin/bash -c "if [ "$$EXIT_STATUS" != 0 ]; then /usr/local/bin/discord-ml-fail-alert.sh; fi"
ExecStopPost=/usr/bin/bash -c "if [ "$$EXIT_STATUS" != 0 ]; then /usr/local/bin/post-on-discord.sh -c infra_alert -m 'ML training job failed for {{domain_name}}'; fi"
4 changes: 4 additions & 0 deletions infra/ansible/roles/django/templates/post-on-discord.sh.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env bash

cd /srv/tournesol-backend && SETTINGS_FILE=/etc/tournesol/settings.yaml ./venv/bin/python manage.py send_on_discord "$@"
echo "alert sent"
5 changes: 5 additions & 0 deletions infra/ansible/roles/django/templates/settings.yaml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,8 @@ TWITTERBOT_CREDENTIALS:
"ACCESS_TOKEN": "{{access_token_twitterbot_en}}",
"ACCESS_TOKEN_SECRET": "{{access_token_secret_twitterbot_en}}",
}

DISCORD_CHANNEL_WEBHOOKS: {
infra_alert: "{{ discord_infra_alert_webhook }}",
twitter: "{{ discord_twitter_webhook }}",
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ Group=gunicorn
WorkingDirectory=/srv/tournesol-backend
Environment="SETTINGS_FILE=/etc/tournesol/settings.yaml"
ExecStart=/usr/bin/bash -c "source venv/bin/activate && python manage.py cleartokens"
ExecStopPost=/usr/bin/bash -c "if [ "$$EXIT_STATUS" != 0 ]; then /usr/local/bin/discord-tournesolapi-cleartokens-fail-alert.sh; fi"
ExecStopPost=/usr/bin/bash -c "if [ "$$EXIT_STATUS" != 0 ]; then /usr/local/bin/post-on-discord.sh -c infra_alert -m 'Tournesol API cleartokens job failed for {{domain_name}}'; fi"
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ Group=gunicorn
WorkingDirectory=/srv/tournesol-backend
Environment="SETTINGS_FILE=/etc/tournesol/settings.yaml"
ExecStart=/usr/bin/bash -c "source venv/bin/activate && python manage.py delete_inactive_users"
ExecStopPost=/usr/bin/bash -c "if [ "$$EXIT_STATUS" != 0 ]; then /usr/local/bin/discord-tournesolapi-deleteinactiveusers-fail-alert.sh; fi"
ExecStopPost=/usr/bin/bash -c "if [ "$$EXIT_STATUS" != 0 ]; then /usr/local/bin/post-on-discord.sh -c infra_alert -m 'Tournesol API delete_inactive_users job failed for {{ansible_host}}'; fi"
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ ExecStart=/usr/bin/bash -c "source venv/bin/activate && \
python manage.py run_twitterbot -y --bot-name '@TournesolBot';; \
*) ;; \
esac"
ExecStopPost=/usr/bin/bash -c "if [ "$$EXIT_STATUS" != 0 ]; then /usr/local/bin/discord-twitterbot-fail-alert.sh; fi"
ExecStopPost=/usr/bin/bash -c "if [ "$$EXIT_STATUS" != 0 ]; then /usr/local/bin/post-on-discord.sh -c infra_alert -m 'run_twitterbot job failed for {{domain_name}}'; fi"
4 changes: 2 additions & 2 deletions infra/ansible/roles/frontend/handlers/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@

- name: Notify frontend upgrade
shell:
cmd: "wget -qO /dev/null --post-data='{\"content\": \"**{{domain_name}}** - new front end deployed: {{git_reference}}\"}' --header='Content-Type:application/json' '{{discord_alerting_webhook}}?wait=true'"
cmd: "wget -qO /dev/null --post-data='{\"content\": \"**{{domain_name}}** - new front end deployed: {{git_reference}}\"}' --header='Content-Type:application/json' '{{discord_infra_alert_webhook}}?wait=true'"
executable: /usr/bin/bash
when: discord_alerting_webhook is defined and discord_alerting_webhook != ""
when: discord_infra_alert_webhook is defined and discord_infra_alert_webhook != ""

- name: Create Frontend OAuth application in Django database
shell:
Expand Down
14 changes: 4 additions & 10 deletions infra/ansible/roles/monitoring/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@
- libxshmfence1 # will be needed soon
install_recommends: no
update_cache: yes
when: discord_alerting_webhook is defined and discord_alerting_webhook != ""
when: discord_infra_alert_webhook is defined and discord_infra_alert_webhook != ""

- name: Set permissions on Grafana plugins directory
file:
Expand All @@ -316,7 +316,7 @@
with_items:
- name: grafana-image-renderer
version: "3.2.1"
when: discord_alerting_webhook is defined and discord_alerting_webhook != ""
when: discord_infra_alert_webhook is defined and discord_infra_alert_webhook != ""
notify: Enable and restart Grafana

- name: Create Discord notification channel
Expand All @@ -329,11 +329,11 @@
uid: discord
name: Tournesol Discord
type: discord
discord_url: "{{discord_alerting_webhook}}"
discord_url: "{{discord_infra_alert_webhook}}"
is_default: yes
include_image: yes
reminder_frequency: 5m
when: discord_alerting_webhook is defined and discord_alerting_webhook != ""
when: discord_infra_alert_webhook is defined and discord_infra_alert_webhook != ""

- name: Create Grafana dashboards
community.grafana.grafana_dashboard:
Expand Down Expand Up @@ -366,12 +366,6 @@
- grafana_oidc_client_id
- grafana_oidc_client_secret

- name: Write Discord alerting webhook into root's home
template:
dest: /root/discord_alerting_webhook
src: discord_alerting_webhook.j2
mode: u=rw,go=

- name: Copy external URLs monitoring script
template:
dest: /usr/local/bin/external-urls-monitoring.sh
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ do
echo "checking $u"
wget -qO /dev/null "$u" && echo "$u OK" || (
echo "error checking $u"
{% if discord_alerting_webhook is defined and discord_alerting_webhook != "" %}
{% if discord_infra_alert_webhook is defined and discord_infra_alert_webhook != "" %}
wget -qO /dev/null \
--post-data='{"content": "health check of '"$u"' failed"}' \
--header='Content-Type:application/json' \
'{{discord_alerting_webhook}}?wait=true'
'{{discord_infra_alert_webhook}}?wait=true'
echo "alert sent"
{% endif %}
)
Expand Down
8 changes: 1 addition & 7 deletions infra/ansible/roles/postgresql/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,6 @@
install_recommends: no
update_cache: yes

- name: Copy Discord Postgres backup failure alert
template:
dest: /usr/local/bin/postgres-backup-fail-alert.sh
src: discord-postgres-backup-fail-alert.sh.j2
mode: a=rx

- name: Create Postgresql backups directory
file:
state: directory
Expand Down Expand Up @@ -43,7 +37,7 @@

- name: Install Postgresql backups service
template:
src: pg-backups.service
src: pg-backups.service.j2
dest: /etc/systemd/system/pg-backups.service

- name: Install Postgresql backups timer
Expand Down
Loading

0 comments on commit 9f88d2f

Please sign in to comment.