diff --git a/provision-contest/ansible/Makefile b/provision-contest/ansible/Makefile index 06f39de7..13f347cf 100644 --- a/provision-contest/ansible/Makefile +++ b/provision-contest/ansible/Makefile @@ -29,33 +29,33 @@ VENDOR= else VENDOR=roles/domjudge_checkout/files/webapp/vendor $(VENDOR): $(VENDORTGZ) - -cd roles/domjudge_checkout/files/webapp && tar xzf ../$(notdir $<) + -mkdir -p roles/domjudge_checkout/files/webapp && cd roles/domjudge_checkout/files/webapp && tar xzf ../$(notdir $<) endif ROLES=domserver judgehost admin grafana cds presclient presadmin scoreboard mgmt autoanalyst $(ROLES): %: %.yml hosts group_vars/all/secret.yml $(VENDOR) $(SSHKEY) $(SSHKEY).pub - ansible-playbook -i hosts $< + ansible-playbook $< FAILED_ROLES=$(addprefix failed-,$(ROLES)) $(FAILED_ROLES): failed-%: %.yml %.retry - ansible-playbook -i hosts --limit @$*.retry $< + ansible-playbook --limit @$*.retry $< CODEONLY_ROLES=$(addprefix codeonly-,domserver judgehost admin) $(CODEONLY_ROLES): codeonly-%: - ansible-playbook -i hosts --tags pretask,domjudge_build $*.yml + ansible-playbook --tags pretask,domjudge_build $*.yml powerloss: - ansible-playbook -i hosts emergency.yml --tags powerloss + ansible-playbook emergency.yml --tags powerloss lockdown: - ansible-playbook -i hosts emergency.yml --tags full_lockdown + ansible-playbook emergency.yml --tags full_lockdown lockdown-force: - ansible-playbook -i hosts emergency.yml --tags full_lockdown,force_lockdown + ansible-playbook emergency.yml --tags full_lockdown,force_lockdown ansible-master: for book in $(ROLES) ; do \ - ansible-playbook -i hosts $$book.yml --tags install_master ; \ + ansible-playbook $$book.yml --tags install_master ; \ done admin: $(SSL_LOCALHOST_FILES) diff --git a/provision-contest/ansible/README.md b/provision-contest/ansible/README.md index 41c2fa47..b8493c8d 100644 --- a/provision-contest/ansible/README.md +++ b/provision-contest/ansible/README.md @@ -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 diff --git a/provision-contest/ansible/admin.yml b/provision-contest/ansible/admin.yml index e847f41d..410bc2a4 100644 --- a/provision-contest/ansible/admin.yml +++ b/provision-contest/ansible/admin.yml @@ -52,6 +52,7 @@ state: present pkg: - ansible + - ansible-lint - git-gui - gitk - makepasswd diff --git a/provision-contest/ansible/ansible.cfg b/provision-contest/ansible/ansible.cfg index ee6bd190..66a618f3 100644 --- a/provision-contest/ansible/ansible.cfg +++ b/provision-contest/ansible/ansible.cfg @@ -5,6 +5,7 @@ system_warnings = True strategy = free retry_files_enabled = True retry_files_save_path = ~/.ansible-retry +inventory = hosts [connection] ssh_args = -C -o ControlMaster=auto -o ControlPersist=60s diff --git a/provision-contest/ansible/glitchtip.yml b/provision-contest/ansible/glitchtip.yml new file mode 100644 index 00000000..a9673f7c --- /dev/null +++ b/provision-contest/ansible/glitchtip.yml @@ -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 diff --git a/provision-contest/ansible/group_vars/onprem/all.yml.example b/provision-contest/ansible/group_vars/onprem/all.yml.example index 790b227c..b475038b 100644 --- a/provision-contest/ansible/group_vars/onprem/all.yml.example +++ b/provision-contest/ansible/group_vars/onprem/all.yml.example @@ -2,7 +2,7 @@ DJ_DIR: /opt/domjudge # Branch to checkout and use. -DJ_BRANCH: main +DJ_BRANCH: wfastana # Whether to force-pull changes to the checkout, overwriting any local changes. DJ_FORCE_UPDATE: true @@ -11,7 +11,7 @@ DJ_FORCE_UPDATE: true SERVER_IP_PREFIX: 10.3.3 # IP address of the git server. -LOCAL_GIT_IP: "{{SERVER_IP_PREFIX}}.207" +LOCAL_GIT_IP: "{{SERVER_IP_PREFIX}}.209" # URL and IP of domserver from judgehosts. A hostname 'domserver' with # DOMSERVER_IP will be added to the judgehost /etc/hosts file. @@ -22,18 +22,18 @@ 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 +AWS: 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_RESTRICTED_NETWORK: true WF_GREEN: false # Static IP address configuration. Uses the ansible_host variable as the static @@ -55,7 +55,7 @@ HOSTS: domjudge-laptop: 10.3.3.200 pc2: 10.3.3.241 -TIMEZONE: "Europe/Amsterdam" +TIMEZONE: "Asia/Almaty" PHP_FPM_MAX_CHILDREN: 400 PHP_FPM_MAX_REQUESTS: 500 @@ -70,30 +70,9 @@ 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: "wf2021" +CONTEST_REPO: "wfastana" PHPSTORM_VERSION: 2022.2 PHPSTORM_FULL_VERSION: 222.4345.15 GRAFANA_MONITORING: false - -# 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/onprem/analyst-domserver b/provision-contest/ansible/group_vars/onprem/analyst-domserver new file mode 120000 index 00000000..a9bd85e1 --- /dev/null +++ b/provision-contest/ansible/group_vars/onprem/analyst-domserver @@ -0,0 +1 @@ +group_vars/onprem/analyst \ No newline at end of file diff --git a/provision-contest/ansible/group_vars/onprem/analyst-judgehost b/provision-contest/ansible/group_vars/onprem/analyst-judgehost new file mode 120000 index 00000000..a9bd85e1 --- /dev/null +++ b/provision-contest/ansible/group_vars/onprem/analyst-judgehost @@ -0,0 +1 @@ +group_vars/onprem/analyst \ No newline at end of file diff --git a/provision-contest/ansible/group_vars/onprem/analyst/secret.yml.example b/provision-contest/ansible/group_vars/onprem/analyst/secret.yml.example new file mode 100644 index 00000000..01f29718 --- /dev/null +++ b/provision-contest/ansible/group_vars/onprem/analyst/secret.yml.example @@ -0,0 +1,37 @@ +# 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_IP: "{{SERVER_IP_PREFIX}}.240" + +WF_GREEN: true + +# 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: 172.29.1.207 + packages: 172.29.1.209 + ntp1: 172.29.1.208 + ntp2: 172.29.1.209 + nisprint: 172.29.1.211 + nismaster: 172.29.1.211 + printsrv: 172.29.1.211 + +GRAFANA_MONITORING: false + +# 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} + +# Credentials for the judgehost. +JUDGEHOST_PASSWORD: {some-strong-judgehost-password} diff --git a/provision-contest/ansible/group_vars/onprem/secret.yml.example b/provision-contest/ansible/group_vars/onprem/secret.yml.example index 8e86e0ef..6e68cd07 100644 --- a/provision-contest/ansible/group_vars/onprem/secret.yml.example +++ b/provision-contest/ansible/group_vars/onprem/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,8 @@ 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: + +# GlitchTip +# GLITCHTIP_SECRET: {some-strong-glitchtip-password} diff --git a/provision-contest/ansible/group_vars/onprem/wfinal-domserver b/provision-contest/ansible/group_vars/onprem/wfinal-domserver new file mode 120000 index 00000000..b746395e --- /dev/null +++ b/provision-contest/ansible/group_vars/onprem/wfinal-domserver @@ -0,0 +1 @@ +group_vars/onprem/wfinal \ No newline at end of file diff --git a/provision-contest/ansible/group_vars/onprem/wfinal-judgehost b/provision-contest/ansible/group_vars/onprem/wfinal-judgehost new file mode 120000 index 00000000..b746395e --- /dev/null +++ b/provision-contest/ansible/group_vars/onprem/wfinal-judgehost @@ -0,0 +1 @@ +group_vars/onprem/wfinal \ No newline at end of file diff --git a/provision-contest/ansible/group_vars/onprem/wfinal/secret.yml.example b/provision-contest/ansible/group_vars/onprem/wfinal/secret.yml.example new file mode 100644 index 00000000..87aec71f --- /dev/null +++ b/provision-contest/ansible/group_vars/onprem/wfinal/secret.yml.example @@ -0,0 +1,3 @@ +# Password for the MySQL replication user. +# Set this to enable master-master replication between two domservers. +REPLICATION_PASSWORD: {some-strong-replication-password} diff --git a/provision-contest/ansible/hosts b/provision-contest/ansible/hosts new file mode 100644 index 00000000..c442eb63 --- /dev/null +++ b/provision-contest/ansible/hosts @@ -0,0 +1,88 @@ +[all:vars] +ansible_user=root +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. + +[onprem:children] +domserver +judgehost +grafana +scriptserver +admin + +[online:children] +online-domserver +online-judgehost + +[domserver:children] +wfinal-domserver +analyst-domserver + +[wfinal-domserver] +# Set EFI_ORDER onsite for faster boot +#EFI_ORDER='0\,1\,3\,4' +domjudge-primary ansible_host=10.3.3.216 KEEPALIVED_PRIORITY=100 +domjudge-backup ansible_host=10.3.3.217 KEEPALIVED_PRIORITY=99 + +[wfinal-domserver:children] +emergency + +[emergency] +domjudge-laptop ansible_host=10.3.3.199 + +[judgehost:children] +analyst-judgehost +wfinal-judgehost + +[wfinal-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 + +[analyst-judgehost] +green-judgehost1 ansible_host=172.29.1.221 +green-judgehost2 ansible_host=172.29.1.222 +green-judgehost3 ansible_host=172.29.1.223 + +[admin] +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 + +[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 + +[scriptserver] +# During the WFs we use one of the ccsadmin machines +# Doesn't matter which (admin) machine but in the past we used 1 as that runs ansible +domjudge-ccsadmin1 ansible_host=10.3.3.224 + +[analyst-domserver] +# Discuss if we can have this host dualhomed in blue to make management easier.\ +# Looking at the IP sheet that would mean that our emergency laptop needs to move. +domjudge-analyst ansible_host=172.29.1.240 + +[online-domserver] +online-domserver ansible_host=192.168.255.255 + +[online-judgehost] +online-judgehost1 ansible_host=192.168.255.255 diff --git a/provision-contest/ansible/roles/base_packages/files/install-docker/.gitignore b/provision-contest/ansible/roles/base_packages/files/install-docker/.gitignore new file mode 100644 index 00000000..c00df136 --- /dev/null +++ b/provision-contest/ansible/roles/base_packages/files/install-docker/.gitignore @@ -0,0 +1 @@ +*.deb diff --git a/provision-contest/ansible/roles/clusterssh/files/tmux-cssh b/provision-contest/ansible/roles/clusterssh/files/tmux-cssh new file mode 100644 index 00000000..41862edf --- /dev/null +++ b/provision-contest/ansible/roles/clusterssh/files/tmux-cssh @@ -0,0 +1,130 @@ +#!/bin/sh + +hosts="" +ssh_options="" +tmux_name="cssh" +tmux_attach_current_session="false" + +usage() { + echo "Usage: $0 [options] host [host ...]" >&2 + echo "" >&2 + echo "Spawns multiple synchronized SSH sessions inside a tmux session." >&2 + echo "" >&2 + echo "Options:" >&2 + echo " -h Show help" >&2 + echo " -c Use the current tmux session and just spawn a new window instead" >&2 + echo " -n Name of the tmux session or window (default: cssh)" >&2 + echo " -o Additional SSH arguments" >&2 +} + +while [ $# -ne 0 ]; do + case $1 in + -n) + shift + if [ $# -eq 0 ]; then + usage + exit 2 + fi + tmux_name="$1" + shift + ;; + -c) + tmux_attach_current_session="true" + shift + ;; + -o) + shift + if [ $# -eq 0 ]; then + usage + exit 2 + fi + ssh_options="$1" + shift + ;; + -h) + usage + exit 0 + ;; + -*) + usage + exit 2 + ;; + *) + hosts="${hosts}${hosts:+ }$1" + shift + ;; + esac +done + +if [ -z "${hosts}" ]; then + usage + exit 2 +fi + +# Find a name for a new session +n=0 +while tmux has-session -t "${tmux_name}-${n}" 2>/dev/null; do n=$((n + 1)); done +tmux_session="${tmux_name}-${n}" + +if [ "${tmux_attach_current_session}" = "true" ]; then + tmux_session="$(tmux display-message -p '#S')" + # Find a name for a new window + n=0 + while tmux list-windows -F "#W" | grep -q "${tmux_name}-${n}" 2>/dev/null; do n=$((n + 1)); done + tmux_window="${tmux_name}-${n}" + tmux_window_options="-n ${tmux_window}" +fi + +# If host doesn't look like a DNS name, it may be a CSSH cluster +if ! echo "${hosts}" | grep -q '[. ]'; then + for cfg in "${HOME}/.clusterssh/clusters" /etc/clusters; do + if [ -r "${cfg}" ]; then + h="$(sed -n "s/^${hosts} //p" <"${cfg}")" + if [ -n "${h}" ]; then + hosts="${h}" + break + fi + fi + # If there was no corresponding cluster name, + # just assume we have an unqualified domain name + done +fi + +# Open a new session and split into new panes for each SSH session +for host in ${hosts}; do + if ! tmux has-session -t "${tmux_session}" 2>/dev/null; then + tmux new-session -s "${tmux_session}" -d "ssh ${ssh_options} ${host}" + elif [ "${tmux_attach_current_session}" = "true" ]; then + if ! tmux list-windows -F "#W" | grep -q "${tmux_window}" >/dev/null; then + # shellcheck disable=SC2086 + tmux new-window ${tmux_window_options} "ssh ${ssh_options} ${host}" + else + tmux split-window -t "${tmux_window}" -d "ssh ${ssh_options} ${host}" + # We have to reset the layout after each new pane otherwise the panes + # quickly become too small to spawn any more + tmux select-layout -t "${tmux_session}" tiled + fi + else + tmux split-window -t "${tmux_session}" -d "ssh ${ssh_options} ${host}" + # We have to reset the layout after each new pane otherwise the panes + # quickly become too small to spawn any more + tmux select-layout -t "${tmux_session}" tiled + fi +done + +# Synchronize panes by default +if [ "${tmux_attach_current_session}" = "true" ]; then + tmux set-window-option -t "${tmux_window}" synchronize-panes on +else + tmux set-window-option -t "${tmux_session}" synchronize-panes on +fi + +if [ -n "${TMUX}" ]; then + # We are in a tmux, just switch to the new session + tmux switch-client -t "${tmux_session}" +else + # We are NOT in a tmux, attach to the new session + tmux attach-session -t "${tmux_session}" +fi + +exit 0 diff --git a/provision-contest/ansible/roles/clusterssh/tasks/main.yml b/provision-contest/ansible/roles/clusterssh/tasks/main.yml index 585432da..af39787b 100644 --- a/provision-contest/ansible/roles/clusterssh/tasks/main.yml +++ b/provision-contest/ansible/roles/clusterssh/tasks/main.yml @@ -22,3 +22,46 @@ src: clusters.j2 dest: /home/domjudge/.clusterssh/clusters mode: 0644 + +- name: Install tmux-cssh + when: not WF_RESTRICTED_NETWORK + get_url: + url: https://raw.githubusercontent.com/peikk0/tmux-cssh/master/tmux-cssh + dest: /usr/local/bin/tmux-cssh + mode: 0755 + owner: root + group: root + +- name: Install tmux-cssh + when: WF_RESTRICTED_NETWORK + copy: + src: tmux-cssh + dest: /usr/local/bin/tmux-cssh + mode: 0755 + owner: root + group: root + +- name: Set tmux-cssh shorthands + template: + owner: root + group: root + mode: 0755 + src: tmux-cluster.sh.j2 + dest: /usr/local/bin/{{ item.short }} + loop: + - short: ssh-jh + group: wfinal-judgehost + - short: ssh-jhanalyst + group: analyst-judgehost + - short: ssh-jhall + group: judgehost + - short: ssh-dom + group: wfinal-domserver + - short: ssh-domanalyst + group: analyst-domserver + - short: ssh-domall + group: domserver + - short: ssh-all + group: onprem + - short: ssh-admin + group: admin diff --git a/provision-contest/ansible/roles/clusterssh/templates/tmux-cluster.sh.j2 b/provision-contest/ansible/roles/clusterssh/templates/tmux-cluster.sh.j2 new file mode 100644 index 00000000..a995a600 --- /dev/null +++ b/provision-contest/ansible/roles/clusterssh/templates/tmux-cluster.sh.j2 @@ -0,0 +1,3 @@ +#!/usr/bin/sh + +tmux-cssh {% for host in groups[item.group] %}{{ host }} {% endfor %} diff --git a/provision-contest/ansible/roles/docker/files/README.md b/provision-contest/ansible/roles/docker/files/README.md new file mode 100644 index 00000000..2eafe9e8 --- /dev/null +++ b/provision-contest/ansible/roles/docker/files/README.md @@ -0,0 +1,5 @@ +# Loading containers from archives +Any container `.tar` files placed in a `containers-` directory will be loaded as a container for the said host type. +The container will be tagged with the relative path starting from `containers-`, 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. diff --git a/provision-contest/ansible/roles/docker/files/containers-glitchtip/.gitignore b/provision-contest/ansible/roles/docker/files/containers-glitchtip/.gitignore new file mode 100644 index 00000000..d874ad67 --- /dev/null +++ b/provision-contest/ansible/roles/docker/files/containers-glitchtip/.gitignore @@ -0,0 +1 @@ +*.tar diff --git a/provision-contest/ansible/roles/docker/files/containers-glitchtip/glitchtip/.gitignore b/provision-contest/ansible/roles/docker/files/containers-glitchtip/glitchtip/.gitignore new file mode 100644 index 00000000..72e8ffc0 --- /dev/null +++ b/provision-contest/ansible/roles/docker/files/containers-glitchtip/glitchtip/.gitignore @@ -0,0 +1 @@ +* diff --git a/provision-contest/ansible/roles/docker/files/docker.asc b/provision-contest/ansible/roles/docker/files/docker.asc new file mode 100644 index 00000000..ee7872e5 --- /dev/null +++ b/provision-contest/ansible/roles/docker/files/docker.asc @@ -0,0 +1,62 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +YT90qFF93M3v01BbxP+EIY2/9tiIPbrd +=0YYh +-----END PGP PUBLIC KEY BLOCK----- diff --git a/provision-contest/ansible/roles/docker/tasks/load-container.yml b/provision-contest/ansible/roles/docker/tasks/load-container.yml new file mode 100644 index 00000000..1f4c6df2 --- /dev/null +++ b/provision-contest/ansible/roles/docker/tasks/load-container.yml @@ -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 }}" diff --git a/provision-contest/ansible/roles/docker/tasks/main.yml b/provision-contest/ansible/roles/docker/tasks/main.yml new file mode 100644 index 00000000..c9fefb38 --- /dev/null +++ b/provision-contest/ansible/roles/docker/tasks/main.yml @@ -0,0 +1,34 @@ +--- +- name: Add Docker GPG apt Key + apt_key: + data: "{{ lookup('ansible.builtin.file', 'docker.asc') }}" + state: present + +- name: Add Docker Repository + 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 + +- name: Remove executable bit from "/usr/local/bin/runc" + 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" diff --git a/provision-contest/ansible/roles/docker/vars/.gitignore b/provision-contest/ansible/roles/docker/vars/.gitignore new file mode 100644 index 00000000..1cda54be --- /dev/null +++ b/provision-contest/ansible/roles/docker/vars/.gitignore @@ -0,0 +1 @@ +*.yml diff --git a/provision-contest/ansible/roles/domjudge_checkout/files/.gitignore b/provision-contest/ansible/roles/domjudge_checkout/files/.gitignore index 13ecffc5..1a2afa60 100644 --- a/provision-contest/ansible/roles/domjudge_checkout/files/.gitignore +++ b/provision-contest/ansible/roles/domjudge_checkout/files/.gitignore @@ -1,3 +1,4 @@ /lib /lib-vendor.tgz /vendor.tgz +/webapp diff --git a/provision-contest/ansible/roles/glitchtip/defaults/main.yml b/provision-contest/ansible/roles/glitchtip/defaults/main.yml new file mode 100644 index 00000000..b09e4f05 --- /dev/null +++ b/provision-contest/ansible/roles/glitchtip/defaults/main.yml @@ -0,0 +1 @@ +GLITCHTIP_PORT: 8000 diff --git a/provision-contest/ansible/roles/glitchtip/handlers/main.yml b/provision-contest/ansible/roles/glitchtip/handlers/main.yml new file mode 100644 index 00000000..61571dfd --- /dev/null +++ b/provision-contest/ansible/roles/glitchtip/handlers/main.yml @@ -0,0 +1,7 @@ +--- +- name: Restart GlitchTip + community.docker.docker_compose_v2: + project_src: /opt/glitchtip + files: + - docker-compose.yaml + state: restarted diff --git a/provision-contest/ansible/roles/glitchtip/tasks/main.yml b/provision-contest/ansible/roles/glitchtip/tasks/main.yml new file mode 100644 index 00000000..ddc85269 --- /dev/null +++ b/provision-contest/ansible/roles/glitchtip/tasks/main.yml @@ -0,0 +1,17 @@ +--- +- name: Create directories + become_user: root + file: + path: /opt/glitchtip + state: directory + +- name: Create compose file + template: + src: templates/docker-compose.yaml.j2 + dest: /opt/glitchtip/docker-compose.yaml + +- name: Deploy GlitchTip compose stack + community.docker.docker_compose_v2: + project_src: /opt/glitchtip + files: + - docker-compose.yaml diff --git a/provision-contest/ansible/roles/glitchtip/templates/docker-compose.yaml.j2 b/provision-contest/ansible/roles/glitchtip/templates/docker-compose.yaml.j2 new file mode 100644 index 00000000..b36fe45a --- /dev/null +++ b/provision-contest/ansible/roles/glitchtip/templates/docker-compose.yaml.j2 @@ -0,0 +1,55 @@ +# Uncomment version if using an older version of docker compose +# version: "3.8" +x-environment: + &default-environment + DATABASE_URL: postgres://postgres:postgres@postgres:5432/postgres + SECRET_KEY: {{ GLITCHTIP_SECRET }} + PORT: {{ GLITCHTIP_PORT}} + EMAIL_URL: consolemail:// + GLITCHTIP_DOMAIN: http://glitchtip:{{ GLITCHTIP_PORT }} + DEFAULT_FROM_EMAIL: email@glitchtip + CELERY_WORKER_AUTOSCALE: "1,1" + CELERY_WORKER_MAX_TASKS_PER_CHILD: "1000" + +x-depends_on: + &default-depends_on + - postgres + - redis + +services: + postgres: + image: postgres:16-alpine + environment: + POSTGRES_HOST_AUTH_METHOD: "trust" # Consider removing this and setting a password + restart: unless-stopped + volumes: + - pg-data:/var/lib/postgresql/data + redis: + image: redis:7-alpine + restart: unless-stopped + web: + image: glitchtip/glitchtip:v4.1.3 + depends_on: *default-depends_on + ports: + - {{ GLITCHTIP_PORT }}:{{ GLITCHTIP_PORT }} + environment: *default-environment + restart: unless-stopped + volumes: + - uploads:/code/uploads + worker: + image: glitchtip/glitchtip:v4.1.3 + command: ./bin/run-celery-with-beat.sh + depends_on: *default-depends_on + environment: *default-environment + restart: unless-stopped + volumes: + - uploads:/code/uploads + migrate: + image: glitchtip/glitchtip:v4.1.3 + depends_on: *default-depends_on + command: ./bin/run-migrate.sh + environment: *default-environment + +volumes: + pg-data: + uploads: diff --git a/provision-contest/ansible/roles/glitchtip/vars/.gitignore b/provision-contest/ansible/roles/glitchtip/vars/.gitignore new file mode 100644 index 00000000..1cda54be --- /dev/null +++ b/provision-contest/ansible/roles/glitchtip/vars/.gitignore @@ -0,0 +1 @@ +*.yml diff --git a/provision-contest/ansible/roles/grafana/templates/prometheus.yml.j2 b/provision-contest/ansible/roles/grafana/templates/prometheus.yml.j2 index 8352c07c..d9e1f262 100644 --- a/provision-contest/ansible/roles/grafana/templates/prometheus.yml.j2 +++ b/provision-contest/ansible/roles/grafana/templates/prometheus.yml.j2 @@ -24,8 +24,8 @@ scrape_configs: - {{ hostvars[host].ansible_host }}:9100 {% endfor %} {% endif %} -{% if groups["domserver"][0] is defined %} - - job_name: {{ group_prefix ~ domjudge }} +{% if groups[group_prefix+"domserver"][0] is defined %} + - job_name: {{ group_prefix ~ 'domserver' }} basic_auth: username: admin password: {{ ADMIN_PASSWORD }} diff --git a/provision-contest/ansible/roles/judgedaemon/tasks/main.yml b/provision-contest/ansible/roles/judgedaemon/tasks/main.yml index 9e9234bb..74001b70 100644 --- a/provision-contest/ansible/roles/judgedaemon/tasks/main.yml +++ b/provision-contest/ansible/roles/judgedaemon/tasks/main.yml @@ -34,7 +34,13 @@ dest: /tmp/dj_ansible/ - name: Create chroot - shell: "set -o pipefail && {{ DJ_DIR }}/misc-tools/dj_make_chroot -y -i openjdk-17-jdk-headless -l \"$(ls /tmp/dj_ansible/install-chroot/*.deb 2>/dev/null | tr '\n' ',')\" -s \"$(ls /tmp/dj_ansible/chroot-list/*.list 2>/dev/null | tr '\n' ',')\" 2>&1 | tee /tmp/dj_make_chroot.log; grep '^Done building chroot in' /tmp/dj_make_chroot.log" + shell: "set -o pipefail && + {{ DJ_DIR }}/misc-tools/dj_make_chroot -y -H + -i icpc-kotlinc,openjdk-17-jdk-headless + -l \"$(ls /tmp/dj_ansible/install-chroot/*.deb 2>/dev/null | tr '\n' ',')\" + -s \"$(ls /tmp/dj_ansible/chroot-list/*.list 2>/dev/null | tr '\n' ',')\" + 2>&1 | tee /tmp/dj_make_chroot.log; + grep '^Done building chroot in' /tmp/dj_make_chroot.log" environment: DEBMIRROR: "{%- if WF_RESTRICTED_NETWORK and ICPC_IMAGE -%}https://packages/ubuntu {%- elif ICPC_IMAGE -%}https://sysopspackages.icpc.global/ubuntu diff --git a/provision-contest/ansible/roles/script_server/defaults/main.yml b/provision-contest/ansible/roles/script_server/defaults/main.yml new file mode 100644 index 00000000..f6d568c9 --- /dev/null +++ b/provision-contest/ansible/roles/script_server/defaults/main.yml @@ -0,0 +1,55 @@ +--- +SCRIPT_SERVER_PORT: 5000 + +script_server_commands: + - name: make-invocations + description: Run the make targets as last years + parameters: + - name: make_pattern + type: multiselect + separator: ' ' + values: + - admin + - domserver + - judgehost + - grafana + - cds + content: | + #!/bin/bash + set -euxo pipefail + if [ "$make_pattern" = "" ]; then + exit 1 + fi + cd /home/domjudge/domjudge-scripts-checkout/provision-contest/ansible + for make_single in $make_pattern; do + make "$make_single" + done + - name: ansible-admin + description: (Re)configure the (other) admin machines + content: | + #!/bin/bash + set -euxo pipefail + if [ "$host_pattern" = "" ]; then + exit 1 + fi + if [ "$tag_pattern" != "" ]; then + tag="--tags $tag_pattern" + fi + cd /home/domjudge/domjudge-scripts-checkout/provision-contest/ansible + ansible-playbook --limit $host_pattern ${tag:-} admin.yml + parameters: + - name: host_pattern + # pass_as: env_variable # this is default + # env_var: host_pattern # default is same as name + type: multiselect + values: "{{ groups['admin'] }}" + default: "{{ groups['admin'] | difference(['domjudge-ccsadmin2']) }}" + - name: tag_pattern + type: "multiselect" + values: ["reboot"] + default: [] + +script_server_command_defaults: + output_format: terminal + # scheduling: # Don't allow scheduling, the ui for it is not good... + # enabled: false diff --git a/provision-contest/ansible/roles/script_server/files/.gitignore b/provision-contest/ansible/roles/script_server/files/.gitignore new file mode 100644 index 00000000..c4c4ffc6 --- /dev/null +++ b/provision-contest/ansible/roles/script_server/files/.gitignore @@ -0,0 +1 @@ +*.zip diff --git a/provision-contest/ansible/roles/script_server/handlers/main.yml b/provision-contest/ansible/roles/script_server/handlers/main.yml new file mode 100644 index 00000000..1e3e86a1 --- /dev/null +++ b/provision-contest/ansible/roles/script_server/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: Restart script-server + ansible.builtin.service: + name: script-server + state: restarted diff --git a/provision-contest/ansible/roles/script_server/tasks/main.yml b/provision-contest/ansible/roles/script_server/tasks/main.yml new file mode 100644 index 00000000..de770b7a --- /dev/null +++ b/provision-contest/ansible/roles/script_server/tasks/main.yml @@ -0,0 +1,89 @@ +--- +- name: Install script-server dependencies + apt: + name: + - python3-tornado + - apache2-utils # for htpasswd auth + state: present + +- name: Create directory for script-server to live + file: + path: /opt/script-server + mode: "0755" + owner: root + group: root + state: directory + +- name: Install script-server + when: ICPC_IMAGE + unarchive: + src: "script-server.zip" + dest: /opt/script-server + remote_src: false + creates: /opt/script-server/launcher.py + +- name: Install script-server + when: not ICPC_IMAGE + unarchive: + src: "https://github.com/bugy/script-server/releases/download/1.18.0/script-server.zip" + dest: /opt/script-server + remote_src: true + creates: /opt/script-server/launcher.py + +- name: Configure the server + template: + src: conf.json.j2 + dest: /opt/script-server/conf/conf.json + mode: "0644" + owner: root + group: root + +- name: Create systemd service for script-server + notify: Restart script-server + copy: + mode: "0644" + dest: /etc/systemd/system/script-server.service + content: | + [Unit] + Description=Script Server + After=network.target + StartLimitIntervalSec=0 + + [Service] + Type=simple + Restart=always + RestartSec=1 + ExecStart=/usr/bin/python3 /opt/script-server/launcher.py + + [Install] + WantedBy=multi-user.target + +- name: Ensure required directories exist + file: + state: directory + mode: "0755" + path: /opt/script-server/conf/{{ item }} + loop: + - scripts + - runners + +- name: Create scripts + copy: + content: "{{ item.content }}" + dest: /opt/script-server/conf/scripts/{{ item.name }} + mode: "0755" + with_items: "{{ script_server_commands }}" + +- name: Create script config definitions + ansible.builtin.template: + src: command_template.yml.j2 + dest: /opt/script-server/conf/runners/{{ item.name }}.yaml + mode: "0644" + with_items: "{{ script_server_commands }}" + +- name: Start + enable script-server + service: + name: script-server + state: started + enabled: true + diff --git a/provision-contest/ansible/roles/script_server/templates/command_template.yml.j2 b/provision-contest/ansible/roles/script_server/templates/command_template.yml.j2 new file mode 100644 index 00000000..367b3c0f --- /dev/null +++ b/provision-contest/ansible/roles/script_server/templates/command_template.yml.j2 @@ -0,0 +1,44 @@ +--- +{% set _unused_content = item.pop('content') %} +{% set parameters = item.pop('parameters', []) %} +{% set admin_users = groups['admin'] %} +{% set allowed_users = groups['onprem'] %} +{# set admin_users = (admin_users if ( admin_users | type_debug == "list" ) else [admin_users]) #} +{# set allowed_users = (allowed_users if ( allowed_users | type_debug == "list" ) else [allowed_users]) #} +{{ + script_server_command_defaults | + combine(item) | + to_nice_yaml +}} + +{% if admin_users %} +admin_users: + - 127.0.0.1 +{% for u in admin_users %} + - {{ hostvars[u].ansible_host }} +{% endfor %} +{% endif %} +{% if allowed_users %} +skipped_allowed_users: + - 127.0.0.1 +{% for u in (allowed_users + admin_users)|unique %} + - {{ hostvars[u].ansible_host }} +{% endfor %} +{% endif %} + +{% if parameters %} +parameters: +{% for param in parameters %} + - name: {{ param.name }} + pass_as: {{ param.pass_as | default('env_variable') }} +{% if param.pass_as|default('env_variable') == 'env_variable' %} + env_var: {{ param.env_var | default(param.name) }} +{% endif %} +{% for k,v in param.items() if k not in ['pass_as','env_var','name'] %} + {{ k}}: {{ v|to_json }} +{% endfor %} +{% endfor %} +{% endif %} + +# assume default path for the script file +script_path: conf/scripts/{{ item.name }} diff --git a/provision-contest/ansible/roles/script_server/templates/conf.json.j2 b/provision-contest/ansible/roles/script_server/templates/conf.json.j2 new file mode 100644 index 00000000..3fcfa8b4 --- /dev/null +++ b/provision-contest/ansible/roles/script_server/templates/conf.json.j2 @@ -0,0 +1,19 @@ +{ + "title": "sysops script server", + "port": {{ SCRIPT_SERVER_PORT }}, + "access": { + "admin_users": [ + {%- for host in groups['admin'] -%} + "{{ hostvars[host].ansible_host}}", + {% endfor %} + "127.0.0.1" + ] + }, + "logging": { + "execution_file": "$DATE-$ID.log", + "execution_date_format": "%y-%m-%d_%H-%M" + }, + "security": { + "xsrf_protection": "token" + } +} diff --git a/provision-contest/ansible/scriptserver.yml b/provision-contest/ansible/scriptserver.yml new file mode 100644 index 00000000..cabbf334 --- /dev/null +++ b/provision-contest/ansible/scriptserver.yml @@ -0,0 +1,20 @@ +--- + +- hosts: scriptserver + vars: + host_type: scriptserver + become: true + handlers: + - include: 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: script_server + tags: script_server