diff --git a/domlogo/domlogo.py b/domlogo/domlogo.py index 9ea1edb0..636ceb58 100755 --- a/domlogo/domlogo.py +++ b/domlogo/domlogo.py @@ -10,6 +10,29 @@ import platform import shlex import yaml +from PIL import Image, ImageDraw, ImageFont + + +def generate_placeholder(text: str, path: str, background_color, width: int, height: int): + image = Image.new("RGB", (width, height), background_color) + draw = ImageDraw.Draw(image) + font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 72) + text_bbox = draw.textbbox((0, 0), text, font=font) + text_width = text_bbox[2] - text_bbox[0] + text_height = text_bbox[3] - text_bbox[1] + text_x = (width - text_width) / 2 + text_y = (height - text_height) / 2 + draw.text((text_x, text_y), text, fill=(255,255,255), font=font) + + # Add some hint how to replace the image. + small_font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 16) + placeholder_text = f'(Replace this placeholder image at {path})' + text_bbox = draw.textbbox((0, 0), placeholder_text, font=small_font) + text_width = text_bbox[2] - text_bbox[0] + text_x = (width - text_width) / 2 + text_y = text_y + 1.4*text_height + draw.text((text_x, text_y), placeholder_text, fill=(195,196,199), font=small_font) + image.save(path) def download_image(image_type: str, entity_id: str, file: dict): @@ -26,6 +49,7 @@ def download_image(image_type: str, entity_id: str, file: dict): if existing_etag != etag: print(f'Downloading and converting {image_type} for entity with ID {entity_id}...') + os.makedirs(os.path.dirname(temp_file), exist_ok=True) with open(temp_file, 'wb') as f: f.write(requests.get(f'{api_url}/{href}', auth=(user, passwd)).content) @@ -39,6 +63,11 @@ def download_image(image_type: str, entity_id: str, file: dict): host = platform.node() host_bg_color = 'black' +idle_image = 'domlogo-files/photos/idle.png' +if not os.path.isfile(idle_image): + os.makedirs(os.path.dirname(idle_image), exist_ok=True) + generate_placeholder('judgehost idle', idle_image, (10,75,120), 1024, 768) + config_file = 'domlogo-files/config.yaml' if os.path.isfile(config_file) and os.access(config_file, os.R_OK): with open(config_file, 'r') as f: @@ -172,7 +201,7 @@ def download_image(image_type: str, entity_id: str, file: dict): last_seen = (submission_id, judging_id, team_id) new_filename = f'domlogo-files/photos/{team_id}.png' if not os.path.isfile(new_filename): - new_filename = f'domlogo-files/photos/crew.png' + generate_placeholder(f'team {team_id}', new_filename, (137,28,28), 1024, 768) team_image.update(filename=new_filename) metadata_text.update(f's{submission_id} / {submission_data["problem_id"]} / {submission_data["language_id"]}') results_text.update('Busy compiling.') diff --git a/provision-contest/ansible/Makefile b/provision-contest/ansible/Makefile index e4f20073..435b5543 100644 --- a/provision-contest/ansible/Makefile +++ b/provision-contest/ansible/Makefile @@ -15,6 +15,8 @@ LIBVENDORTGZ=roles/domjudge_checkout/files/lib-vendor.tgz SSHKEY=roles/ssh/files/id_ed25519 SSL_DOMSERVER=roles/ssl/files/domserver SSL_DOMSERVER_FILES=$(addprefix $(SSL_DOMSERVER),.key .crt) +SSL_NODEEXPORT=roles/prometheus_target_all/files/node_exporter +SSL_NODEEXPORT_FILES=$(addprefix $(SSL_NODEEXPORT),.key .crt) SSL_LOCALHOST=roles/ssl/files/localhost SSL_LOCALHOST_FILES=$(addprefix $(SSL_LOCALHOST),.key .crt) SSL_CDS=roles/ssl/files/cds @@ -57,9 +59,12 @@ ansible-master: done admin: $(SSL_LOCALHOST_FILES) -grafana: $(SSL_GRAFANA_FILES) -domserver: $(SSL_DOMSERVER_FILES) -cds: $(SSL_CDS_FILES) +grafana: $(SSL_GRAFANA_FILES) $(SSL_NODEEXPORT) +domserver: $(SSL_DOMSERVER_FILES) $(SSL_NODEEXPORT) +judgehost: $(SSL_NODEEXPORT) +cds: $(SSL_CDS_FILES) $(SSL_NODEEXPORT) +scoreboard: $(SSL_NODEEXPORT) +mgmt: $(SSL_NODEEXPORT) $(SSHKEY) $(SSHKEY).pub: ssh-keygen -t ed25519 -f $(SSHKEY) -P '' @@ -68,6 +73,9 @@ $(SSL_DOMSERVER_FILES): openssl req -x509 -nodes -newkey rsa:4096 -subj "/O=DOMjudge/CN=domjudge" \ -addext "subjectAltName = DNS:wf46-domjudge,DNS:wf47-domjudge,DNS:analyst" \ -sha256 -days 365 -keyout $(SSL_DOMSERVER).key -out $(SSL_DOMSERVER).crt +$(SSL_NODEEXPORT_FILES): + openssl req -x509 -nodes -newkey rsa:4096 -subj "/O=DOMjudge/CN=metricexporter" \ + -sha256 -days 365 -keyout $(SSL_NODEEXPORT).key -out $(SSL_NODEEXPORT).crt $(SSL_LOCALHOST_FILES): openssl req -x509 -nodes -newkey rsa:4096 -subj "/O=DOMjudge/CN=localhost" \ -sha256 -days 365 -keyout $(SSL_LOCALHOST).key -out $(SSL_LOCALHOST).crt @@ -84,6 +92,7 @@ clean: distclean: clean rm -f $(SSHKEY) $(SSHKEY).pub rm -f $(SSL_DOMSERVER_FILES) + rm -f $(SSL_NODEEXPORT) rm -f $(SSL_LOCALHOST_FILES) rm -f $(SSL_CDS_FILES) rm -f $(SSL_GRAFANA_FILES) diff --git a/provision-contest/ansible/group_vars/admin.yml b/provision-contest/ansible/group_vars/admin.yml index ca98b241..2026ccca 100644 --- a/provision-contest/ansible/group_vars/admin.yml +++ b/provision-contest/ansible/group_vars/admin.yml @@ -8,3 +8,5 @@ PHP_FPM_MAX_CHILDREN: 5 DOMSERVER_SSL_CERT: /etc/ssl/certs/localhost.crt DOMSERVER_SSL_KEY: /etc/ssl/private/localhost.key + +DB_DUMP_PREFIX: admin diff --git a/provision-contest/ansible/group_vars/all/all.yml.example b/provision-contest/ansible/group_vars/all/all.yml.example index 2649424c..91aa020b 100644 --- a/provision-contest/ansible/group_vars/all/all.yml.example +++ b/provision-contest/ansible/group_vars/all/all.yml.example @@ -2,7 +2,7 @@ DJ_DIR: /opt/domjudge # Branch to checkout and use. -DJ_BRANCH: main +DJ_BRANCH: wfluxor # Whether to force-pull changes to the checkout, overwriting any local changes. DJ_FORCE_UPDATE: true @@ -16,16 +16,15 @@ LOCAL_GIT_IP: "{{SERVER_IP_PREFIX}}.207" # URL and IP of domserver from judgehosts. A hostname 'domserver' with # DOMSERVER_IP will be added to the judgehost /etc/hosts file. DOMSERVER: https://domjudge -DOMSERVER_IP: "{{SERVER_IP_PREFIX}}.215" -DOMSERVER_URL: "{{DOMSERVER}}" +DOMSERVER_URL: "{{ DOMSERVER }}" DOMSERVER_SSL_CERT: /etc/ssl/certs/domserver.crt DOMSERVER_SSL_KEY: /etc/ssl/private/domserver.key # Set this to true when you are using the ICPC World Finals Contest Image -ICPC_IMAGE: false +ICPC_IMAGE: true # Set this to true when you are using a graphical desktop -GRAPHICAL: false +GRAPHICAL: true # Set this to true when you use an (ICPC) AWS machine AWS: true @@ -33,8 +32,9 @@ AWS: true # Set this when on the blue network at the World Finals where no # internet access is available and "packages" must be used as APT repo # server. -WF_RESTRICTED_NETWORK: false +WF_RESTRICTED_NETWORK: true WF_GREEN: false +HOSTS_DNS: false # Static IP address configuration. Uses the ansible_host variable as the static # IP address. Only configured if STATIC_IP_ENABLED is true. @@ -55,7 +55,7 @@ HOSTS: domjudge-laptop: 10.3.3.200 pc2: 10.3.3.241 -TIMEZONE: "Europe/Amsterdam" +TIMEZONE: "Africa/Cairo" PHP_FPM_MAX_CHILDREN: 400 PHP_FPM_MAX_REQUESTS: 500 @@ -65,17 +65,17 @@ PHP_POST_MAX_SIZE: 256M PHP_MAX_FILE_UPLOADS: 101 # Git repo URL -DJ_GIT_HOST: "{{LOCAL_GIT_IP}}" +DJ_GIT_HOST: "{{ LOCAL_GIT_IP }}" DJ_GIT_REPO: "https://github.com/domjudge/domjudge.git" -DJ_GIT_REPO_RESTRICTED: "domjudge@{{DJ_GIT_HOST}}:domjudge" +DJ_GIT_REPO_RESTRICTED: "domjudge@{{ DJ_GIT_HOST }}:domjudge" DJ_GIT_REPO_SCRIPTS: "https://github.com/domjudge/domjudge-scripts.git" -DJ_GIT_REPO_SCRIPTS_RESTRICTED: "domjudge@{{DJ_GIT_HOST}}:domjudge-scripts-bare" -CONTEST_REPO: "wf2021" +DJ_GIT_REPO_SCRIPTS_RESTRICTED: "domjudge@{{ DJ_GIT_HOST }}:domjudge-scripts-bare" +CONTEST_REPO: "wfluxor" -PHPSTORM_VERSION: 2022.2 -PHPSTORM_FULL_VERSION: 222.4345.15 +PHPSTORM_VERSION: 2024.1 +PHPSTORM_FULL_VERSION: 241.14494.237 -GRAFANA_MONITORING: false +GRAFANA_MONITORING: true # Hostname of the CDS. If set, will add an nginx in front of the CDS # If not set, will only expose CDS directly diff --git a/provision-contest/ansible/group_vars/all/secret.yml.example b/provision-contest/ansible/group_vars/all/secret.yml.example index 8e86e0ef..3144c239 100644 --- a/provision-contest/ansible/group_vars/all/secret.yml.example +++ b/provision-contest/ansible/group_vars/all/secret.yml.example @@ -4,10 +4,6 @@ # Adding `strong` in the template will create longer passwords and is used for the # passwords which almost never need to be manually typed. -# Password for the MySQL replication user. -# Set this to enable master-master replication between two domservers. -#REPLICATION_PASSWORD: {some-strong-replication-password} - # Database user password. DB_PASSWORD: {some-strong-database-password} @@ -24,48 +20,5 @@ ADMIN_PASSWORD: {some-admin-password} # created on the domserver and judgehosts. #DJ_SHELL_USER_PW: {some-hashed-password} -# Accounts to create when setting up the CDS -CDS_ACCOUNTS: - - username: admin - password: {some-adm1n-password} - type: admin - - username: presAdmin - password: {some-presentation-adm1n-password} - type: admin - - username: presentation - password: {some-public-presentation-password} - type: public - #- username: blue - # password: blu3 - # type: staff - #- username: balloon - # password: balloonPr1nter - # type: balloon - #- username: public - # password: publ1c - # type: public - #- username: myicpc - # password: my1cpc - # type: spectator - #- username: live - # password: l1ve - # type: analyst - #- username: team1 - # password: t3am - # type: team - # team_id: 1 - -# Contest(s) to configure in the CDS -CDS_CONTESTS: - - path: nwerc18 # Path in the contest directory - ccs: - id: nwerc18 # ID of the contest if hosted at DOMJUDGE_URL - # Or provide a absolute URL - # url: https://www.domjudge.org/demoweb/api/contests/nwerc18 - username: admin - password: admin - -PRESCLIENT_CONTEST: nwerc18 - # Sentry DSN URL # SENTRY_DSN: diff --git a/provision-contest/ansible/group_vars/analyst-domserver b/provision-contest/ansible/group_vars/analyst-domserver new file mode 120000 index 00000000..d8d431bc --- /dev/null +++ b/provision-contest/ansible/group_vars/analyst-domserver @@ -0,0 +1 @@ +analyst \ No newline at end of file diff --git a/provision-contest/ansible/group_vars/analyst-judgehost b/provision-contest/ansible/group_vars/analyst-judgehost new file mode 120000 index 00000000..d8d431bc --- /dev/null +++ b/provision-contest/ansible/group_vars/analyst-judgehost @@ -0,0 +1 @@ +analyst \ No newline at end of file diff --git a/provision-contest/ansible/group_vars/analyst/.gitignore b/provision-contest/ansible/group_vars/analyst/.gitignore new file mode 100644 index 00000000..c35135b1 --- /dev/null +++ b/provision-contest/ansible/group_vars/analyst/.gitignore @@ -0,0 +1,2 @@ +/secret.yml +/all.yml diff --git a/provision-contest/ansible/group_vars/analyst/all.yml.example b/provision-contest/ansible/group_vars/analyst/all.yml.example new file mode 100644 index 00000000..3a605e08 --- /dev/null +++ b/provision-contest/ansible/group_vars/analyst/all.yml.example @@ -0,0 +1,15 @@ +# Server VLAN IP prefix. +SERVER_IP_PREFIX: 172.29.1 + +# URL and IP of domserver from judgehosts. A hostname 'domserver' with +# DOMSERVER_IP will be added to the judgehost /etc/hosts file. +DOMSERVER: https://domjudge +DOMSERVER_IP: "{{SERVER_IP_PREFIX}}.240" + +# Set this when on the blue network at the World Finals where no +# internet access is available and "packages" must be used as APT repo +# server. +WF_GREEN: true +HOSTS_DNS: true + +DB_DUMP_PREFIX: analyst diff --git a/provision-contest/ansible/group_vars/analyst/secret.yml.example b/provision-contest/ansible/group_vars/analyst/secret.yml.example new file mode 100644 index 00000000..b8f66a37 --- /dev/null +++ b/provision-contest/ansible/group_vars/analyst/secret.yml.example @@ -0,0 +1,2 @@ +DB_PASSWORD: {some-strong-database-password-analyst} +JUDGEHOST_PASSWORD: {some-strong-judgehost-password-analyst} diff --git a/provision-contest/ansible/group_vars/online-domserver b/provision-contest/ansible/group_vars/online-domserver new file mode 120000 index 00000000..5f2de0e9 --- /dev/null +++ b/provision-contest/ansible/group_vars/online-domserver @@ -0,0 +1 @@ +online \ No newline at end of file diff --git a/provision-contest/ansible/group_vars/online-judgehost b/provision-contest/ansible/group_vars/online-judgehost new file mode 120000 index 00000000..5f2de0e9 --- /dev/null +++ b/provision-contest/ansible/group_vars/online-judgehost @@ -0,0 +1 @@ +online \ No newline at end of file diff --git a/provision-contest/ansible/group_vars/online/.gitignore b/provision-contest/ansible/group_vars/online/.gitignore new file mode 100644 index 00000000..c35135b1 --- /dev/null +++ b/provision-contest/ansible/group_vars/online/.gitignore @@ -0,0 +1,2 @@ +/secret.yml +/all.yml diff --git a/provision-contest/ansible/group_vars/online/all.yml.example b/provision-contest/ansible/group_vars/online/all.yml.example new file mode 100644 index 00000000..d81346ee --- /dev/null +++ b/provision-contest/ansible/group_vars/online/all.yml.example @@ -0,0 +1,95 @@ +# Directory of the domjudge repository checkout. +DJ_DIR: /opt/domjudge + +# Branch to checkout and use. +DJ_BRANCH: wfonline + +# Whether to force-pull changes to the checkout, overwriting any local changes. +DJ_FORCE_UPDATE: true + +# Server VLAN IP prefix. +SERVER_IP_PREFIX: 10.3.3 + +# IP address of the git server. +LOCAL_GIT_IP: "{{SERVER_IP_PREFIX}}.207" + +# URL and IP of domserver from judgehosts. A hostname 'domserver' with +# DOMSERVER_IP will be added to the judgehost /etc/hosts file. +DOMSERVER: https://domjudge +DOMSERVER_URL: "{{ DOMSERVER }}" +DOMSERVER_SSL_CERT: /etc/ssl/certs/domserver.crt +DOMSERVER_SSL_KEY: /etc/ssl/private/domserver.key + +# Set this to true when you are using the ICPC World Finals Contest Image +ICPC_IMAGE: false + +# Set this to true when you are using a graphical desktop +GRAPHICAL: false + +# Set this when on the blue network at the World Finals where no +# internet access is available and "packages" must be used as APT repo +# server. +WF_RESTRICTED_NETWORK: false +WF_GREEN: false + +# Static IP address configuration. Uses the ansible_host variable as the static +# IP address. Only configured if STATIC_IP_ENABLED is true. +STATIC_IP_ENABLED: false +STATIC_IP_NETMASK: 255.255.252.0 +STATIC_IP_GATEWAY: 172.29.0.1 +STATIC_IP_INTERFACE: enp1s0 + +# Additional entries for the /etc/hosts file. +HOSTS: + cds: 10.3.3.207 + packages: 10.3.3.209 + ntp1: 10.3.3.208 + ntp2: 10.3.3.209 + nisprint: 10.3.3.211 + nismaster: 10.3.3.211 + printsrv: 10.3.3.211 + domjudge-laptop: 10.3.3.200 + pc2: 10.3.3.241 + +TIMEZONE: "Asia/Dhaka" + +PHP_FPM_MAX_CHILDREN: 400 +PHP_FPM_MAX_REQUESTS: 500 +PHP_MEMORY_LIMIT: 1024M +PHP_UPLOAD_MAX_FILESIZE: 256M +PHP_POST_MAX_SIZE: 256M +PHP_MAX_FILE_UPLOADS: 101 + +# Git repo URL +DJ_GIT_HOST: "{{ LOCAL_GIT_IP }}" +DJ_GIT_REPO: "https://github.com/domjudge/domjudge.git" +DJ_GIT_REPO_RESTRICTED: "domjudge@{{ DJ_GIT_HOST }}:domjudge" +DJ_GIT_REPO_SCRIPTS: "https://github.com/domjudge/domjudge-scripts.git" +DJ_GIT_REPO_SCRIPTS_RESTRICTED: "domjudge@{{ DJ_GIT_HOST }}:domjudge-scripts-bare" +CONTEST_REPO: "wfluxor" + +PHPSTORM_VERSION: 2022.2 +PHPSTORM_FULL_VERSION: 222.4345.15 + +GRAFANA_MONITORING: true + +# Hostname of the CDS. If set, will add an nginx in front of the CDS +# If not set, will only expose CDS directly +CDS_HOSTNAME: cds +CDS_PORT: 80 +CDS_PORT_SECURE: 443 + +# CDS SSL cert and key. Only needed when CDS_HOSTNAME is set +CDS_SSL_CERT: /etc/ssl/certs/cds.crt +CDS_SSL_KEY: /etc/ssl/private/cds.key + +# Hostname of the static scoreboard +STATIC_SCOREBOARD_HOSTNAME: scoreboard + +STATIC_SCOREBOARD_SSL_CERT: /etc/ssl/certs/scoreboard.crt +STATIC_SCOREBOARD_SSL_KEY: /etc/ssl/private/scoreboard.key + +# Block access to the CDS for IPs other than these +#CDS_IP_FILTER: +# - 127.0.0.1-127.0.0.1 +# - 192.168.0.0-192.168.255.255 diff --git a/provision-contest/ansible/group_vars/online/secret.yml.example b/provision-contest/ansible/group_vars/online/secret.yml.example new file mode 100644 index 00000000..9ff95a06 --- /dev/null +++ b/provision-contest/ansible/group_vars/online/secret.yml.example @@ -0,0 +1,9 @@ +DB_PASSWORD: {some-strong-database-password-online} + +# Credentials for the judgehost. +JUDGEHOST_USER: judgehost +JUDGEHOST_PASSWORD: {some-strong-judgehost-password-online} + +# Username and password to be used in .netrc files on admin machines +ADMIN_USER: admin +ADMIN_PASSWORD: {some-admin-password-online} diff --git a/provision-contest/ansible/group_vars/wf46-domserver b/provision-contest/ansible/group_vars/wf46-domserver new file mode 120000 index 00000000..f4c9917d --- /dev/null +++ b/provision-contest/ansible/group_vars/wf46-domserver @@ -0,0 +1 @@ +wf46 \ No newline at end of file diff --git a/provision-contest/ansible/group_vars/wf46-judgehost b/provision-contest/ansible/group_vars/wf46-judgehost new file mode 120000 index 00000000..f4c9917d --- /dev/null +++ b/provision-contest/ansible/group_vars/wf46-judgehost @@ -0,0 +1 @@ +wf46 \ No newline at end of file diff --git a/provision-contest/ansible/group_vars/wf46/.gitignore b/provision-contest/ansible/group_vars/wf46/.gitignore new file mode 100644 index 00000000..c35135b1 --- /dev/null +++ b/provision-contest/ansible/group_vars/wf46/.gitignore @@ -0,0 +1,2 @@ +/secret.yml +/all.yml diff --git a/provision-contest/ansible/group_vars/wf46/all.yml.example b/provision-contest/ansible/group_vars/wf46/all.yml.example new file mode 100644 index 00000000..76ffbeb5 --- /dev/null +++ b/provision-contest/ansible/group_vars/wf46/all.yml.example @@ -0,0 +1,6 @@ +# URL and IP of domserver from judgehosts. A hostname 'domserver' with +# DOMSERVER_IP will be added to the judgehost /etc/hosts file. +DOMSERVER: https://domserver-wf46 +DOMSERVER_IP: "{{SERVER_IP_PREFIX}}.215" + +DB_DUMP_PREFIX: 46 diff --git a/provision-contest/ansible/group_vars/wf46/secret.yml.example b/provision-contest/ansible/group_vars/wf46/secret.yml.example new file mode 100644 index 00000000..10d7c121 --- /dev/null +++ b/provision-contest/ansible/group_vars/wf46/secret.yml.example @@ -0,0 +1,3 @@ +REPLICATION_PASSWORD: {some-strong-replication-password-wf46} +DB_PASSWORD: {some-strong-database-password-wf46} +JUDGEHOST_PASSWORD: {some-strong-judgehost-password-wf46} diff --git a/provision-contest/ansible/group_vars/wf47-domserver b/provision-contest/ansible/group_vars/wf47-domserver new file mode 120000 index 00000000..93589e28 --- /dev/null +++ b/provision-contest/ansible/group_vars/wf47-domserver @@ -0,0 +1 @@ +wf47 \ No newline at end of file diff --git a/provision-contest/ansible/group_vars/wf47-judgehost b/provision-contest/ansible/group_vars/wf47-judgehost new file mode 120000 index 00000000..93589e28 --- /dev/null +++ b/provision-contest/ansible/group_vars/wf47-judgehost @@ -0,0 +1 @@ +wf47 \ No newline at end of file diff --git a/provision-contest/ansible/group_vars/wf47/.gitignore b/provision-contest/ansible/group_vars/wf47/.gitignore new file mode 100644 index 00000000..c35135b1 --- /dev/null +++ b/provision-contest/ansible/group_vars/wf47/.gitignore @@ -0,0 +1,2 @@ +/secret.yml +/all.yml diff --git a/provision-contest/ansible/group_vars/wf47/all.yml.example b/provision-contest/ansible/group_vars/wf47/all.yml.example new file mode 100644 index 00000000..5a08e5c3 --- /dev/null +++ b/provision-contest/ansible/group_vars/wf47/all.yml.example @@ -0,0 +1,6 @@ +# URL and IP of domserver from judgehosts. A hostname 'domserver' with +# DOMSERVER_IP will be added to the judgehost /etc/hosts file. +DOMSERVER: https://domjudge-wf47 +DOMSERVER_IP: "{{SERVER_IP_PREFIX}}.218" + +DB_DUMP_PREFIX: 47 diff --git a/provision-contest/ansible/group_vars/wf47/secret.yml.example b/provision-contest/ansible/group_vars/wf47/secret.yml.example new file mode 100644 index 00000000..edbd62de --- /dev/null +++ b/provision-contest/ansible/group_vars/wf47/secret.yml.example @@ -0,0 +1,3 @@ +REPLICATION_PASSWORD: {some-strong-replication-password-wf47} +DB_PASSWORD: {some-strong-database-password-wf47} +JUDGEHOST_PASSWORD: {some-strong-judgehost-password-wf47} diff --git a/provision-contest/ansible/hosts.example b/provision-contest/ansible/hosts.example index 72409204..dae3032b 100644 --- a/provision-contest/ansible/hosts.example +++ b/provision-contest/ansible/hosts.example @@ -4,43 +4,114 @@ ansible_python_interpreter=/usr/bin/python3 # When moving clients for ad-hoc actions: # move them to their own group to keep hosts files on deployed machines in sync. - -[domserver] -domjudge-primary ansible_host=10.3.3.216 KEEPALIVED_PRIORITY=100 EFI_ORDER='0\,1\,3\,4' -domjudge-backup ansible_host=10.3.3.217 KEEPALIVED_PRIORITY=99 EFI_ORDER='0\,1\,3\,4' +[ad-hoc-group] +# untargetted-domserver ansible_host=10.1.1.1 [domserver:children] -emergency - -[emergency] -domjudge-laptop ansible_host=10.3.3.218 - -[judgehost] -domjudge-judgehost1 ansible_host=10.2.2.192 -domjudge-judgehost2 ansible_host=10.2.2.193 -domjudge-judgehost3 ansible_host=10.2.2.194 -domjudge-judgehost4 ansible_host=10.2.2.195 -domjudge-judgehost5 ansible_host=10.2.2.196 -domjudge-judgehost6 ansible_host=10.2.2.197 -domjudge-judgehost7 ansible_host=10.2.2.198 -domjudge-judgehost8 ansible_host=10.2.2.199 -domjudge-judgehost9 ansible_host=10.2.2.200 -domjudge-judgehost10 ansible_host=10.2.2.201 -domjudge-judgehost11 ansible_host=10.2.2.202 -domjudge-judgehost12 ansible_host=10.2.2.203 -domjudge-judgehost13 ansible_host=10.2.2.204 -domjudge-judgehost14 ansible_host=10.2.2.205 -domjudge-judgehost15 ansible_host=10.2.2.206 -domjudge-judgehost16 ansible_host=10.2.2.207 -domjudge-judgehost17 ansible_host=10.2.2.208 -domjudge-judgehost18 ansible_host=10.2.2.209 +wf46-domserver +wf47-domserver +analyst-domserver +online-domserver + +[wf46-domserver] +domjudge-wf46-primary ansible_host=10.3.3.216 +domjudge-wf46-secondary ansible_host=10.3.3.217 + +[wf46-domserver:children] +wf46-emergency + +[wf46-emergency] +wf46-emerg ansible_host=10.3.3.240 + +[wf47-domserver] +domjudge-wf47-primary ansible_host=10.3.3.219 +domjudge-wf47-secondary ansible_host=10.3.3.220 + +[wf47-domserver:children] +wf47-emergency + +[wf47-emergency] +wf47-emerg ansible_host=10.3.3.241 + +[analyst-domserver] +domjudge-analyst ansible_host=172.29.1.240 + +[online-domserver] +domjudge-aws ansible_host=0.0.0.0 + +[judgehost:children] +wf46-judgehost +wf47-judgehost +analyst-judgehost +online-judgehost + +[wf46-judgehost] +domjudge-judge-wf46-1 ansible_host=10.2.2.192 +domjudge-judge-wf46-2 ansible_host=10.2.2.193 +domjudge-judge-wf46-3 ansible_host=10.2.2.194 +domjudge-judge-wf46-4 ansible_host=10.2.2.195 +domjudge-judge-wf46-5 ansible_host=10.2.2.196 +domjudge-judge-wf46-6 ansible_host=10.2.2.197 +domjudge-judge-wf46-7 ansible_host=10.2.2.198 +domjudge-judge-wf46-8 ansible_host=10.2.2.199 +domjudge-judge-wf46-9 ansible_host=10.2.2.200 +domjudge-judge-wf46-10 ansible_host=10.2.2.201 +domjudge-judge-wf46-11 ansible_host=10.2.2.202 +domjudge-judge-wf46-12 ansible_host=10.2.2.203 +domjudge-judge-wf46-13 ansible_host=10.2.2.204 +domjudge-judge-wf46-14 ansible_host=10.2.2.205 +domjudge-judge-wf46-15 ansible_host=10.2.2.206 +domjudge-judge-wf46-16 ansible_host=10.2.2.207 + +[wf47-judgehost] +domjudge-judge-wf47-17 ansible_host=10.2.2.208 +domjudge-judge-wf47-18 ansible_host=10.2.2.209 +domjudge-judge-wf47-19 ansible_host=10.2.2.210 +domjudge-judge-wf47-20 ansible_host=10.2.2.211 +domjudge-judge-wf47-21 ansible_host=10.2.2.212 +domjudge-judge-wf47-22 ansible_host=10.2.2.213 +domjudge-judge-wf47-23 ansible_host=10.2.2.214 +domjudge-judge-wf47-24 ansible_host=10.2.2.215 +domjudge-judge-wf47-25 ansible_host=10.2.2.216 +domjudge-judge-wf47-26 ansible_host=10.2.2.217 +domjudge-judge-wf47-27 ansible_host=10.2.2.218 +domjudge-judge-wf47-28 ansible_host=10.2.2.219 +domjudge-judge-wf47-29 ansible_host=10.2.2.220 +domjudge-judge-wf47-30 ansible_host=10.2.2.221 +domjudge-judge-wf47-31 ansible_host=10.2.2.222 +domjudge-judge-wf47-32 ansible_host=10.2.2.223 + +[analyst-judgehost] +analyst-judge1 ansible_host=172.29.1.221 +analyst-judge2 ansible_host=172.29.1.222 +analyst-judge3 ansible_host=172.29.1.223 +analyst-judge4 ansible_host=172.29.1.224 +analyst-judge5 ansible_host=172.29.1.225 +analyst-judge6 ansible_host=172.29.1.226 +analyst-judge7 ansible_host=172.29.1.227 +analyst-judge8 ansible_host=172.29.1.228 +analyst-judge9 ansible_host=172.29.1.229 +# These are the reserved ccsadmins in green +#analyst-judge10 ansible_host=172.29.1.216 +#analyst-judge11 ansible_host=172.29.1.217 +#analyst-judge12 ansible_host=172.29.1.218 + +[online-judgehost] +domjudge-aws ansible_host=0.0.0.0 [admin] -domjudge-ccsadmin1 ansible_host=10.3.3.223 -domjudge-ccsadmin2 ansible_host=10.3.3.224 -domjudge-ccsadmin3 ansible_host=10.3.3.225 -domjudge-ccsadmin4 ansible_host=10.3.3.226 -domjudge-ccsadmin5 ansible_host=10.3.3.227 +domjudge-ccsadmin1 ansible_host=10.3.3.224 +domjudge-ccsadmin2 ansible_host=10.3.3.225 +domjudge-ccsadmin3 ansible_host=10.3.3.226 +domjudge-ccsadmin4 ansible_host=10.3.3.227 +domjudge-ccsadmin5 ansible_host=10.3.3.228 +domjudge-ccsadmin6 ansible_host=10.3.3.229 +domjudge-ccsadmin7 ansible_host=10.3.3.230 +domjudge-ccsadmin9 ansible_host=10.3.3.231 +# These are the reserved ccsadmins in green, also in judgehost group +#green-ccsadmin1 ansible_host=172.29.1.216 +#green-cssadmin2 ansible_host=172.29.1.217 +#green-cssadmin3 ansible_host=172.29.1.218 [grafana] # During the WFs we use one of the ccsadmin machines diff --git a/provision-contest/ansible/roles/base_packages/defaults/main.yml b/provision-contest/ansible/roles/base_packages/defaults/main.yml index 44cbcb05..bdcc7aff 100644 --- a/provision-contest/ansible/roles/base_packages/defaults/main.yml +++ b/provision-contest/ansible/roles/base_packages/defaults/main.yml @@ -36,8 +36,6 @@ INSTALLED_PACKAGES: - libjsoncpp-dev - libmagic-dev - debootstrap - - texlive-latex-recommended - - texlive-latex-extra - apache2-utils - tig - bat diff --git a/provision-contest/ansible/roles/base_packages/tasks/main.yml b/provision-contest/ansible/roles/base_packages/tasks/main.yml index 9be1abe8..605cc5ac 100644 --- a/provision-contest/ansible/roles/base_packages/tasks/main.yml +++ b/provision-contest/ansible/roles/base_packages/tasks/main.yml @@ -12,10 +12,11 @@ - sources.list - sources.list.d/mono.list - sources.list.d/vscode.list - - sources.list.d/pypy-ubuntu-ppa-buster.list + - sources.list.d/pypy-ubuntu-ppa-jammy.list notify: Run apt update - name: Add packages to hosts file + when: HOSTS_DNS lineinfile: dest: /etc/hosts line: "{{ HOSTS['packages'] }} packages" diff --git a/provision-contest/ansible/roles/clusterssh/tasks/main.yml b/provision-contest/ansible/roles/clusterssh/tasks/main.yml index 180432be..585432da 100644 --- a/provision-contest/ansible/roles/clusterssh/tasks/main.yml +++ b/provision-contest/ansible/roles/clusterssh/tasks/main.yml @@ -7,6 +7,14 @@ pkg: - clusterssh +- name: Create clusterssh clusters file + file: + state: directory + owner: domjudge + group: domjudge + path: /home/domjudge/.clusterssh + mode: 0755 + - name: Create clusterssh clusters file become: true become_user: domjudge diff --git a/provision-contest/ansible/roles/domserver/defaults/main.yml b/provision-contest/ansible/roles/domserver/defaults/main.yml index 7092337a..e2a3a2cf 100644 --- a/provision-contest/ansible/roles/domserver/defaults/main.yml +++ b/provision-contest/ansible/roles/domserver/defaults/main.yml @@ -2,3 +2,5 @@ DOMSERVER_PACKAGES: - nginx - php-fpm - php-intl + - texlive-latex-recommended + - texlive-latex-extra diff --git a/provision-contest/ansible/roles/grafana/tasks/main.yml b/provision-contest/ansible/roles/grafana/tasks/main.yml index d450395b..9e478a7c 100644 --- a/provision-contest/ansible/roles/grafana/tasks/main.yml +++ b/provision-contest/ansible/roles/grafana/tasks/main.yml @@ -66,7 +66,7 @@ - name: Install grafana when: not WF_RESTRICTED_NETWORK apt: - deb: https://dl.grafana.com/enterprise/release/grafana-enterprise_8.4.6_amd64.deb + deb: https://dl.grafana.com/oss/release/grafana_10.4.1_amd64.deb state: present notify: Restart grafana diff --git a/provision-contest/ansible/roles/grafana/templates/prometheus.yml.j2 b/provision-contest/ansible/roles/grafana/templates/prometheus.yml.j2 index 7d34db4e..d7ba872f 100644 --- a/provision-contest/ansible/roles/grafana/templates/prometheus.yml.j2 +++ b/provision-contest/ansible/roles/grafana/templates/prometheus.yml.j2 @@ -16,36 +16,72 @@ scrape_configs: - {{ hostvars[host].ansible_host }}:9104 {% endfor %} - job_name: node_domserver + basic_auth: + username: "prometheus" + password: "{{ PROMETHEUS_PASS }}" + tls_config: + insecure_skip_verify: true + scheme: https static_configs: - targets: {% for host in groups["domserver"] %} - {{ hostvars[host].ansible_host }}:9100 {% endfor %} - job_name: node_judgehost + basic_auth: + username: "prometheus" + password: "{{ PROMETHEUS_PASS }}" + tls_config: + insecure_skip_verify: true + scheme: https static_configs: - targets: {% for host in groups["judgehost"] %} - {{ hostvars[host].ansible_host }}:9100 {% endfor %} - job_name: node_grafana + basic_auth: + username: "prometheus" + password: "{{ PROMETHEUS_PASS }}" + tls_config: + insecure_skip_verify: true + scheme: https static_configs: - targets: {% for host in groups["grafana"] %} - {{ hostvars[host].ansible_host }}:9100 {% endfor %} - job_name: node_mgmt + basic_auth: + username: "prometheus" + password: "{{ PROMETHEUS_PASS }}" + tls_config: + insecure_skip_verify: true + scheme: https static_configs: - targets: {% for host in groups["mgmt"] %} - {{ hostvars[host].ansible_host }}:9100 {% endfor %} - job_name: node_scoreboard + basic_auth: + username: "prometheus" + password: "{{ PROMETHEUS_PASS }}" + tls_config: + insecure_skip_verify: true + scheme: https static_configs: - targets: {% for host in groups["scoreboard"] %} - {{ hostvars[host].ansible_host }}:9100 {% endfor %} - job_name: node_cds + basic_auth: + username: "prometheus" + password: "{{ PROMETHEUS_PASS }}" + tls_config: + insecure_skip_verify: true + scheme: https static_configs: - targets: {% for host in groups["cds"] %} @@ -65,18 +101,36 @@ scrape_configs: - {{ hostvars[host].ansible_host }} {% endfor %} - job_name: 'web_nginx_cds' + basic_auth: + username: "prometheus" + password: "{{ PROMETHEUS_PASS }}" + tls_config: + insecure_skip_verify: true + scheme: https static_configs: - targets: {% for host in groups["cds"] %} - {{ hostvars[host].ansible_host }}:9113 {% endfor %} - job_name: 'web_nginx_scoreboard' + basic_auth: + username: "prometheus" + password: "{{ PROMETHEUS_PASS }}" + tls_config: + insecure_skip_verify: true + scheme: https static_configs: - targets: {% for host in groups["scoreboard"] %} - {{ hostvars[host].ansible_host }}:9113 {% endfor %} - job_name: 'web_nginx_domserver' + basic_auth: + username: "prometheus" + password: "{{ PROMETHEUS_PASS }}" + tls_config: + insecure_skip_verify: true + scheme: https static_configs: - targets: {% for host in groups["domserver"] %} diff --git a/provision-contest/ansible/roles/hosts/tasks/main.yml b/provision-contest/ansible/roles/hosts/tasks/main.yml index 3193aa7e..afed5477 100644 --- a/provision-contest/ansible/roles/hosts/tasks/main.yml +++ b/provision-contest/ansible/roles/hosts/tasks/main.yml @@ -6,6 +6,7 @@ name: "{{ inventory_hostname }}" - name: Set new hosts file + when: HOSTS_DNS template: src: hosts.j2 dest: /etc/hosts diff --git a/provision-contest/ansible/roles/mysql_server/files/dump-db b/provision-contest/ansible/roles/mysql_server/files/dump-db deleted file mode 100644 index a7f2c39d..00000000 --- a/provision-contest/ansible/roles/mysql_server/files/dump-db +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/sh - -create_database_dump () { - sudo mysqldump --opt --skip-lock-tables domjudge | pv | gzip > "/home/domjudge/db-dumps/${1}.sql.gz" -} - -if [ -z "$1" ] -then - echo "Usage dump-db [name]" - echo ".sql.gz will be appended" - exit 1 -fi - -if [ -f "/home/domjudge/db-dumps/${1}.sql.gz" ]; then - while true; do - read -p "Overwrite existing database dump (y/N)? " yn - case $yn in - [Yy]* ) create_database_dump $1; exit 0;; - ''|[Nn]* ) break;; - esac - done -else - create_database_dump $1 -fi - -read -p "Provide prefix or say 'no' to abort. Format: [prefix]-$1 " prefix -case $prefix in - ''|[Nn]o|[Nn] ) exit 2; break;; - * ) create_database_dump ${prefix}-${1}; break;; -esac diff --git a/provision-contest/ansible/roles/mysql_server/tasks/main.yml b/provision-contest/ansible/roles/mysql_server/tasks/main.yml index 0e9a6a9a..968e6bf9 100644 --- a/provision-contest/ansible/roles/mysql_server/tasks/main.yml +++ b/provision-contest/ansible/roles/mysql_server/tasks/main.yml @@ -62,13 +62,18 @@ - db-dumps - bin -- name: Copy database dump/load scripts +- name: Copy database load script copy: - src: "{{ item }}" - dest: /home/domjudge/bin/{{ item }} + src: load-db + dest: /home/domjudge/bin/load-db + owner: domjudge + group: domjudge + mode: 0755 + +- name: Copy modified database dump script + template: + src: dump-db.j2 + dest: /home/domjudge/bin/dump-db owner: domjudge group: domjudge mode: 0755 - loop: - - load-db - - dump-db diff --git a/provision-contest/ansible/roles/mysql_server/templates/dump-db.j2 b/provision-contest/ansible/roles/mysql_server/templates/dump-db.j2 new file mode 100644 index 00000000..f36f1b7f --- /dev/null +++ b/provision-contest/ansible/roles/mysql_server/templates/dump-db.j2 @@ -0,0 +1,23 @@ +#!/bin/sh + +create_database_dump () { + sudo mysqldump --opt --skip-lock-tables domjudge | pv | gzip > "/home/domjudge/db-dumps/{{ DB_DUMP_PREFIX }}-${1}.sql.gz" +} + +if [ -z "$1" ] +then + echo "Usage dump-db [name]" + echo ".sql.gz will be appended" + exit 1 +fi + +if [ -f "/home/domjudge/db-dumps/{{ DB_DUMP_PREFIX }}-${1}.sql.gz" ]; then + while true; do + read -p "Overwrite existing database dump (y/N)? " yn + case $yn in + [Yy]* ) break;; + ''|[Nn]* ) exit 2;; + esac + done +fi +create_database_dump $1 diff --git a/provision-contest/ansible/roles/prometheus_target_all/handlers/main.yml b/provision-contest/ansible/roles/prometheus_target_all/handlers/main.yml index cf1cb7ca..87c6f70f 100644 --- a/provision-contest/ansible/roles/prometheus_target_all/handlers/main.yml +++ b/provision-contest/ansible/roles/prometheus_target_all/handlers/main.yml @@ -5,3 +5,9 @@ enabled: true state: restarted daemon_reload: true + +- name: Restart node-exporter + service: + name: prometheus-node-exporter + enabled: true + state: restarted diff --git a/provision-contest/ansible/roles/prometheus_target_all/tasks/main.yml b/provision-contest/ansible/roles/prometheus_target_all/tasks/main.yml index 3cea2cf1..a509ef4c 100644 --- a/provision-contest/ansible/roles/prometheus_target_all/tasks/main.yml +++ b/provision-contest/ansible/roles/prometheus_target_all/tasks/main.yml @@ -6,3 +6,43 @@ state: present pkg: - prometheus-node-exporter + +- name: Collect prometheus settings + file: + path: /etc/prometheus + owner: root + group: root + mode: 0755 + state: directory + +- name: Install SSL server certificates + copy: + src: "node_exporter.{{ item }}" + dest: "/etc/prometheus/node_exporter.{{ item }}" + owner: root + group: root + mode: 0644 + loop: + - crt + - key + +- name: Get HTPassword + delegate_to: localhost + shell: "echo {{ PROMETHEUS_PASS }} | htpasswd -inBC 10 \"\" | tr -d ':\n'" + register: htpassd_shell + +- name: Set certificate to encrypt node_exporter traffic + template: + owner: prometheus + group: prometheus + mode: 0644 + src: web.yml.j2 + dest: /etc/prometheus/prometheus-authentication.yml + +- name: Scrape with TLS encryption + lineinfile: + dest: /etc/default/prometheus-node-exporter + state: present + regexp: '^ARGS=""' + line: 'ARGS="--web.config /etc/prometheus/prometheus-authentication.yml"' + notify: Restart node-exporter diff --git a/provision-contest/ansible/roles/prometheus_target_web/meta/main.yml b/provision-contest/ansible/roles/prometheus_target_web/meta/main.yml new file mode 100644 index 00000000..24a09a19 --- /dev/null +++ b/provision-contest/ansible/roles/prometheus_target_web/meta/main.yml @@ -0,0 +1,5 @@ +# Role dependencies +--- +dependencies: + - role: prometheus_target_all + tags: prometheus_target_all diff --git a/provision-contest/ansible/roles/prometheus_target_web/tasks/main.yml b/provision-contest/ansible/roles/prometheus_target_web/tasks/main.yml index 47cb1385..069520ae 100644 --- a/provision-contest/ansible/roles/prometheus_target_web/tasks/main.yml +++ b/provision-contest/ansible/roles/prometheus_target_web/tasks/main.yml @@ -16,6 +16,14 @@ - prometheus-mysqld-exporter notify: Restart mysqld-exporter +- name: Scrape mysql exporter with TLS encryption + lineinfile: + dest: /etc/default/prometheus-mysqld-exporter + state: present + regexp: '^ARGS=""' + line: 'ARGS="--web.config /etc/prometheus/prometheus-authentication.yml"' + notify: Restart mysqld-exporter + # Gather PHP-FPM statistics # The exporter from this is currently not in deb sources # so we need to download this from GitHub see the README in files @@ -63,6 +71,9 @@ dest: /etc/nginx/sites-enabled/nginx-status.conf notify: Restart nginx +# In the future add: --web.config /etc/prometheus/prometheus-authentication.yml"' +# see: https://github.com/nginxinc/nginx-prometheus-exporter +# The version at the WFLuxor in the repository is not new enough - name: Prometheus nginx exporter lineinfile: dest: /etc/default/prometheus-nginx-exporter