Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docker and GlitchTip ansible roles #168

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions provision-contest/ansible/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ There are a few places where additional files should/can be added:
* Machine/group specific local packages under `roles/base_packages/files/install-*/`.
* Judgehost chroot local packages under `roles/judgedaemon/files/install-chroot/`.
* The vendor dependencies under `roles/domjudge_checkout/files/vendor.tgz`.
* Machine/group specific docker containers under `roles/docker/files/containers-*/`.

## TODO

Expand Down
2 changes: 2 additions & 0 deletions provision-contest/ansible/admin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
tags: clusterssh
- role: phpstorm
tags: phpstorm
- role: dj_notify
tags: dj_notify
- role: prometheus_target_all
tags: prometheus_target_all
when: GRAFANA_MONITORING
Expand Down
21 changes: 21 additions & 0 deletions provision-contest/ansible/glitchtip.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
- hosts: glitchtip
vars:
host_type: glitchtip
become: true
handlers:
- include_tasks: handlers.yml
roles:
- role: base_packages
tags: base_packages
- role: icpc_fixes
tags: icpc_fixes
when: ICPC_IMAGE
- role: system_fixes
tags: system_fixes
- role: hosts
tags: hosts
- role: docker
tags: docker
- role: glitchtip
tags: glitchtip
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,7 @@ PRESCLIENT_CONTEST: nwerc18

# Sentry DSN URL
# SENTRY_DSN:

# GlitchTip
# GLITCHTIP_SECRET: {some-strong-glitchtip-password}
# GLITCHTIP_PASSWORD: {some-strong-glitchtip-password}
7 changes: 6 additions & 1 deletion provision-contest/ansible/hosts.example
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,12 @@ domjudge-ccsadmin5 ansible_host=10.3.3.227
[grafana]
# During the WFs we use one of the ccsadmin machines
# Doesn't matter which (admin) machine but should not be 1 as that runs ansible
domjudge-ccsadmin2 ansible_host=10.3.3.225
domjudge-ccsadmin2 ansible_host=10.3.3.224

[glitchtip]
# During the WFs we use one of the ccsadmin machines
# Doesn't matter which (admin) machine but should not be 1 as that runs ansible
domjudge-ccsadmin3 ansible_host=10.3.3.225

[cds]
domjudge-cds ansible_host=10.2.2.228
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.deb
3 changes: 3 additions & 0 deletions provision-contest/ansible/roles/dj_notify/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
ALSA_DEVICE: alsa_output.pci-0000_00_1f.3-platform-skl_hda_dsp_generic.HiFi__hw_sofhdadsp__sink
NOTIFICATION_SOUND: /usr/share/sounds/sound-icons/trumpet-12.wav
NOTIFICATION_SOUND_VOLUME: 35536
87 changes: 87 additions & 0 deletions provision-contest/ansible/roles/dj_notify/files/dj_notify.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
from http.server import BaseHTTPRequestHandler, HTTPServer
import json
import subprocess
import gi
import os
import webbrowser
import subprocess
import traceback
gi.require_version('Notify', '0.7')
from gi.repository import Notify

HOSTNAME = "0.0.0.0"
PORT = 9999
ALSA_DEVICE = os.environ['ALSA_DEVICE']
NOTIFICATION_SOUND = os.environ['NOTIFICATION_SOUND']
NOTIFICATION_SOUND_VOLUME = int(os.environ['NOTIFICATION_SOUND_VOLUME'])


def on_notification_closed(notification):
print(f"Notification {notification.id} closed.")


Kevinjil marked this conversation as resolved.
Show resolved Hide resolved
def on_link_click(notification, action, link):
webbrowser.open(link)


def filter_notification(title, body, link):
return not title.startswith("Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException")


class NotifyServer(BaseHTTPRequestHandler):
def create_notification(self, title, body, link):
notification = Notify.Notification.new(title, body)
notification.connect("closed", on_notification_closed)
notification.add_action(
"action_click",
"View in browser",
on_link_click,
link
)
notification.show()


def notification_sound(self, sound):
# Use Popen to launch a non-blocking background process
subprocess.Popen(["paplay", "--volume", str(NOTIFICATION_SOUND_VOLUME), "--device", ALSA_DEVICE, sound])


def do_POST(self):
length = int(self.headers.get('Content-Length'))
body = self.rfile.read(length)
content = json.loads(body)
print(json.dumps(content, indent=2))

att = content['attachments'][0]
title = att['title']
link = att['title_link']
body = att['text']

if filter_notification(title, body, link):
try:
self.create_notification(title, body, link)
except Exception:
print(traceback.format_exc())
try:
self.notification_sound(NOTIFICATION_SOUND)
except Exception:
print(traceback.format_exc())

self.send_response(200)
self.send_header("Content-Type", "text/plain")
self.end_headers()

self.wfile.write(bytes("ok", "utf-8"))


Notify.init("DOMjudge notifications")
server = HTTPServer((HOSTNAME, PORT), NotifyServer)

try:
server.serve_forever()
except KeyboardInterrupt:
pass

# Clean up
server.server_close()
Notify.uninit()
7 changes: 7 additions & 0 deletions provision-contest/ansible/roles/dj_notify/handlers/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
- name: Restart dj_notify
systemd:
name: dj_notify
enabled: true
state: restarted
daemon_reload: true
17 changes: 17 additions & 0 deletions provision-contest/ansible/roles/dj_notify/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
# These tasks install the DOMjudge Notify script

- name: Install dj_notify
copy:
src: "dj_notify.py"
dest: "/home/domjudge/bin/dj_notify.py"
owner: domjudge
group: domjudge
mode: 0755
notify: Restart dj_notify

- name: Copy dj_notify systemd unit file
template:
src: "dj_notify.service.j2"
dest: "/etc/systemd/system/dj_notify.service"
notify: Restart dj_notify
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[Unit]
Description="DOMjudge Notify"
After=network.target

[Service]
Type=simple

Environment=ALSA_DEVICE={{ ALSA_DEVICE }}
Environment=NOTIFICATION_SOUND={{ NOTIFICATION_SOUND }}
Environment=DISPLAY=:0
Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1001/bus
Environment=PULSE_SERVER=/run/user/1001/pulse/native
WorkingDirectory=/home/domjudge
ExecStart=/usr/bin/python3 -u /home/domjudge/bin/dj_notify.py
User=domjudge

Restart=always
RestartSec=3

[Install]
WantedBy=graphical.target
5 changes: 5 additions & 0 deletions provision-contest/ansible/roles/docker/files/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Loading containers from archives
Any container `.tar` files placed in a `containers-<host_type>` directory will be loaded as a container for the said host type.
The container will be tagged with the relative path starting from `containers-<host_type>`, without the `.tar` file extension.
For example, the file `containers-glitchtip/glitchtip/glitchtip:v4.1.3.tar` will be loaded as a container tagged `glitchtip/glitchtip:v4.1.3` for the `glitchtip` host type.
Note that a nested directory structure is needed to tag containers which have both an organization and a container name.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.tar
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*
62 changes: 62 additions & 0 deletions provision-contest/ansible/roles/docker/files/docker.asc
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----

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
YT90qFF93M3v01BbxP+EIY2/9tiIPbrd
=0YYh
-----END PGP PUBLIC KEY BLOCK-----
35 changes: 35 additions & 0 deletions provision-contest/ansible/roles/docker/tasks/load-container.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
- name: Load the container from archive if needed
block:
- name: Check for existing container
community.docker.docker_image_info:
name: "{{ img_name }}"
register: result

- name: Transfer and load the container
block:
- name: Create temp container directory
file:
path: /tmp/dj_ansible
state: directory
owner: root
group: root
mode: 0700

- name: Transfer container archive
copy:
src: "{{ item.src }}"
dest: "{{ img_path }}"
owner: root
group: root
mode: 0700

- name: Import container from archive
community.docker.docker_image:
name: "{{ img_name }}"
load_path: "{{ img_path }}"
source: load
when: not result.images
vars:
img_name: "{{ item.path | splitext | first }}"
img_path: "/tmp/dj_ansible/{{ item.path | basename }}"
39 changes: 39 additions & 0 deletions provision-contest/ansible/roles/docker/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
- name: Add Docker GPG apt Key
apt_key:
data: "{{ lookup('ansible.builtin.file', 'docker.asc') }}"
state: present

- name: Add Docker Repository
when: not WF_RESTRICTED_NETWORK
apt_repository:
repo: deb https://download.docker.com/linux/ubuntu jammy stable
state: present

- name: Install Docker and dependencies
apt:
state: present
install_recommends: false
pkg:
- containerd.io
- docker-buildx-plugin
- docker-ce
- docker-ce-cli
- docker-compose-plugin
- python3-pip
- python3-docker

# The `runc` script interferes with running Docker containers.
# Mark it as not executable such that containers can run normally.
# If the machine does need the `runc` in the image, a custom fix has to be applied.
- name: Remove executable bit from "/usr/local/bin/runc"
when: ICPC_IMAGE
file:
dest: /usr/local/bin/runc
mode: -x

- name: Load container archives
include_tasks: load-container.yml
with_filetree:
- files/containers-{{ host_type }}/
when: item.state == 'file' and (item.path | splitext | last) == ".tar"
1 change: 1 addition & 0 deletions provision-contest/ansible/roles/docker/vars/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.yml
3 changes: 3 additions & 0 deletions provision-contest/ansible/roles/glitchtip/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
GLITCHTIP_PORT: 8000
GLITCHTIP_TOKEN:
GLITCHTIP_WEBHOOK_DOMAIN: domjudge-ccsadmin2
7 changes: 7 additions & 0 deletions provision-contest/ansible/roles/glitchtip/handlers/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
- name: Restart GlitchTip
community.docker.docker_compose_v2:
project_src: /opt/glitchtip
files:
- docker-compose.yaml
state: restarted
30 changes: 30 additions & 0 deletions provision-contest/ansible/roles/glitchtip/tasks/create-monitor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
- name: Fetch the project id
ansible.builtin.uri:
method: GET
return_content: yes
url: "http://localhost:{{ GLITCHTIP_PORT }}/api/0/teams/domjudge/DOMjudge/projects/"
headers:
Authorization: "Bearer {{ GLITCHTIP_TOKEN }}"
register: glitchtip_proj
- name: Store JSON query in a fact due to escaping problems in the string below
set_fact:
TEMP_QUERY0: "[?name=='{{ item }}'].id"
- name: Create an DOMjudge uptime monitor for the project
ansible.builtin.uri:
method: POST
return_content: yes
url: "http://localhost:{{ GLITCHTIP_PORT }}/api/0/organizations/domjudge/monitors/"
status_code: 201
headers:
Authorization: "Bearer {{ GLITCHTIP_TOKEN }}"
body:
expectedBody: ""
expectedStatus: 200
timeout: 5
interval: 2
monitorType: "GET"
url: "https://{{ hostvars[item].ansible_host }}/public"
name: "{{ item }}"
project_id: "{{ glitchtip_proj.json | community.general.json_query(TEMP_QUERY0) | first }}"
body_format: json
Loading
Loading