From 8061b335df60a4bac72f3674359dcfb300d3b4f8 Mon Sep 17 00:00:00 2001 From: transcaffeine Date: Sat, 13 Sep 2025 16:43:19 +0200 Subject: [PATCH] feat(pretix): add ansible role and playbook --- playbooks/pretix.yml | 7 ++++ roles/pretix/README.md | 16 ++++++++++ roles/pretix/defaults/main/config.yml | 32 +++++++++++++++++++ roles/pretix/defaults/main/main.yml | 14 ++++++++ .../pretix/defaults/main/system_packages.yml | 21 ++++++++++++ roles/pretix/defaults/main/systemd.yml | 19 +++++++++++ roles/pretix/defaults/main/user.yml | 7 ++++ roles/pretix/defaults/main/virtualenv.yml | 11 +++++++ roles/pretix/meta/main.yml | 9 ++++++ roles/pretix/tasks/check.yml | 14 ++++++++ roles/pretix/tasks/configure.yml | 9 ++++++ roles/pretix/tasks/deploy-systemd.yml | 19 +++++++++++ roles/pretix/tasks/deploy.yml | 5 +++ roles/pretix/tasks/main.yml | 16 ++++++++++ roles/pretix/tasks/prepare-systemd.yml | 19 +++++++++++ roles/pretix/tasks/prepare.yml | 29 +++++++++++++++++ roles/pretix/templates/pretix.service.j2 | 16 ++++++++++ roles/pretix/vars/main.yml | 7 ++++ 18 files changed, 270 insertions(+) create mode 100644 playbooks/pretix.yml create mode 100644 roles/pretix/README.md create mode 100644 roles/pretix/defaults/main/config.yml create mode 100644 roles/pretix/defaults/main/main.yml create mode 100644 roles/pretix/defaults/main/system_packages.yml create mode 100644 roles/pretix/defaults/main/systemd.yml create mode 100644 roles/pretix/defaults/main/user.yml create mode 100644 roles/pretix/defaults/main/virtualenv.yml create mode 100644 roles/pretix/meta/main.yml create mode 100644 roles/pretix/tasks/check.yml create mode 100644 roles/pretix/tasks/configure.yml create mode 100644 roles/pretix/tasks/deploy-systemd.yml create mode 100644 roles/pretix/tasks/deploy.yml create mode 100644 roles/pretix/tasks/main.yml create mode 100644 roles/pretix/tasks/prepare-systemd.yml create mode 100644 roles/pretix/tasks/prepare.yml create mode 100644 roles/pretix/templates/pretix.service.j2 create mode 100644 roles/pretix/vars/main.yml diff --git a/playbooks/pretix.yml b/playbooks/pretix.yml new file mode 100644 index 0000000..6acaac7 --- /dev/null +++ b/playbooks/pretix.yml @@ -0,0 +1,7 @@ +--- +- name: Install and configure pretix + hosts: "{{ pretix_hosts | default('pretix') }}" + become: "{{ pretix_become | default(true) }}" + gather_facts: "{{ pretix_gather_facts | default(false) }}" + roles: + - role: pretix diff --git a/roles/pretix/README.md b/roles/pretix/README.md new file mode 100644 index 0000000..0199be2 --- /dev/null +++ b/roles/pretix/README.md @@ -0,0 +1,16 @@ +# `finallycoffee.services.pretix` ansible role + + +## Troubleshooting + +### virtualenv + +By default, the virtualenv is located in `/var/lib/pretix/virtualenv`. +This can be controlled by setting `pretix_virtualenv_dir`. + +NOTE: To fix a broken virtualenv, try setting `pretix_virtualenv_state` to `forcereinstall` (see +[`ansible.builtin.pip` on docs.ansible.com](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/pip_module.html)). + +NOTE: To install pip packages or execute migrations in the virtualenv, ansible +needs to become the unprivilated `pretix_user` (default: `pretix`). This might +require having the `acl` system package installed. diff --git a/roles/pretix/defaults/main/config.yml b/roles/pretix/defaults/main/config.yml new file mode 100644 index 0000000..67aa8a3 --- /dev/null +++ b/roles/pretix/defaults/main/config.yml @@ -0,0 +1,32 @@ +--- +pretix_config_instance_name: "My pretix installation" +pretix_config_url: "https://pretix.example.org" +pretix_config_currency: "EUR" +pretix_config_data_dir: "{{ pretix_data_dir }}" +pretix_config_trust_x_forwarded_for: "on" +pretix_config_trust_x_forwarded_proto: "on" + +pretix_config: {} +pretix_default_config: + pretix: + url: "{{ pretix_config_url }}" + instance_name: "{{ pretix_config_instance_name }}" + datadir: "{{ pretix_config_data_dir }}" + trust_x_forwarded_for: "{{ pretix_config_trust_x_forwarded_for }}" + trust_x_forwarded_proto: "{{ pretix_config_trust_x_forwarded_proto }}" + currency: "{{ pretix_config_currency }}" + database: + mail: + redis: + celery: + +pretix_config_merged: >-2 + {{ pretix_default_config | combine(pretix_config | default({}), recursive=True) }} + +pretix_config_file_content: |+2 + {% for kv in (pretix_config_merged | dict2items) %} + [{{ kv.key }}] + {% for entry in ((kv.value | default({}, true)) | dict2items) %} + {{ entry.key }}={{ entry.value }} + {% endfor %} + {% endfor %} diff --git a/roles/pretix/defaults/main/main.yml b/roles/pretix/defaults/main/main.yml new file mode 100644 index 0000000..3cd1b54 --- /dev/null +++ b/roles/pretix/defaults/main/main.yml @@ -0,0 +1,14 @@ +--- +pretix_version: "2025.7.1" +pretix_state: "present" +pretix_deployment_method: "systemd" + +pretix_config_file: "/etc/pretix/pretix.cfg" +pretix_config_file_owner: "{{ pretix_user_id }}" +pretix_config_file_group: "{{ pretix_group_id }}" +pretix_config_file_mode: "0640" +pretix_config_dir: "{{ pretix_config_file | dirname }}" +pretix_install_dir: "/var/lib/pretix" +pretix_virtualenv_dir: "{{ pretix_install_dir }}/virtualenv" +pretix_data_dir: "{{ pretix_install_dir }}/data" +pretix_media_dir: "{{ pretix_data_dir }}/media" diff --git a/roles/pretix/defaults/main/system_packages.yml b/roles/pretix/defaults/main/system_packages.yml new file mode 100644 index 0000000..54c8c3d --- /dev/null +++ b/roles/pretix/defaults/main/system_packages.yml @@ -0,0 +1,21 @@ +--- +pretix_debian_packages: + - "git" + - "build-essential" + - "python3-dev" + - "python3-venv" + - "python3" + - "python3-pip" + - "libxml2-dev" + - "libxslt1-dev" + - "libffi-dev" + - "zlib1g-dev" + - "libssl-dev" + - "gettext" + - "libpq-dev" + - "libjpeg-dev" + - "libopenjp2-7-dev" + +pretix_packages: + "debian": + "12": "{{ pretix_debian_packages }}" diff --git a/roles/pretix/defaults/main/systemd.yml b/roles/pretix/defaults/main/systemd.yml new file mode 100644 index 0000000..0590f01 --- /dev/null +++ b/roles/pretix/defaults/main/systemd.yml @@ -0,0 +1,19 @@ +--- +pretix_systemd_unit_description: "pretix web service" +pretix_systemd_unit_after: "network.target" + +pretix_systemd_service_user: "{{ pretix_user }}" +pretix_systemd_service_group: "{{ pretix_user }}" +pretix_systemd_service_environment: + VIRTUAL_ENV: "{{ pretix_virtualenv_dir }}" +pretix_systemd_service_working_directory: "{{ pretix_install_dir }}" +pretix_systemd_service_exec_start: >-2 + {{ pretix_virtualenv_dir }}/bin/gunicorn pretix.wsgi + --name pretix + --workers 5 + --max-requests 100 + --log-level=info + --bind=127.0.0.1:8345 +pretix_systemd_service_restart: "on-failure" + +pretix_systemd_install_wanted_by: "multi-user.target" diff --git a/roles/pretix/defaults/main/user.yml b/roles/pretix/defaults/main/user.yml new file mode 100644 index 0000000..5236d37 --- /dev/null +++ b/roles/pretix/defaults/main/user.yml @@ -0,0 +1,7 @@ +--- +pretix_user: "pretix" +pretix_user_system: true +pretix_user_create_home: false + +pretix_user_id: "{{ pretix_user_info.uid | default(pretix_user) }}" +pretix_group_id: "{{ pretix_user_info.group | default(pretix_user) }}" diff --git a/roles/pretix/defaults/main/virtualenv.yml b/roles/pretix/defaults/main/virtualenv.yml new file mode 100644 index 0000000..8d947ae --- /dev/null +++ b/roles/pretix/defaults/main/virtualenv.yml @@ -0,0 +1,11 @@ +--- +pretix_virtualenv_state: "{{ pretix_state }}" +pretix_virtualenv_packages: + - "pip" + - "setuptools" + - "wheel" + - "gunicorn" + - "pretix=={{ pretix_version }}" + +pretix_virtualenv_site_packages: false +pretix_virtualenv_command: "virtualenv" diff --git a/roles/pretix/meta/main.yml b/roles/pretix/meta/main.yml new file mode 100644 index 0000000..bbd0558 --- /dev/null +++ b/roles/pretix/meta/main.yml @@ -0,0 +1,9 @@ +--- +allow_duplicates: true +dependencies: [] +galaxy_info: + role_name: pretix + description: Ansible role to deploy pretix (https://pretix.eu) + galaxy_tags: + - pretix + - ticketing diff --git a/roles/pretix/tasks/check.yml b/roles/pretix/tasks/check.yml new file mode 100644 index 0000000..04088f2 --- /dev/null +++ b/roles/pretix/tasks/check.yml @@ -0,0 +1,14 @@ +--- +- name: Ensure 'pretix_state' is valid + ansible.builtin.fail: + msg: >-2 + Unsupported pretix_state '{{ pretix_state }}'. + Supported states are {{ pretix_states | join(', ') }} + when: pretix_state not in pretix_states + +- name: Ensure 'pretix_deployment_method' is valid + ansible.builtin.fail: + msg: >-2 + Unsupported pretix_state '{{ pretix_deployment_method }}'. + Supported states are {{ pretix_deployment_methods | join(', ') }} + when: pretix_deployment_method not in pretix_deployment_methods diff --git a/roles/pretix/tasks/configure.yml b/roles/pretix/tasks/configure.yml new file mode 100644 index 0000000..830ac69 --- /dev/null +++ b/roles/pretix/tasks/configure.yml @@ -0,0 +1,9 @@ +--- +- name: Ensure configuration file is written + ansible.builtin.copy: + dest: "{{ pretix_config_file }}" + content: "{{ pretix_config_file_content }}" + owner: "{{ pretix_config_file_owner }}" + group: "{{ pretix_config_file_group }}" + mode: "{{ pretix_config_file_mode }}" + when: pretix_state == 'present' diff --git a/roles/pretix/tasks/deploy-systemd.yml b/roles/pretix/tasks/deploy-systemd.yml new file mode 100644 index 0000000..f75783d --- /dev/null +++ b/roles/pretix/tasks/deploy-systemd.yml @@ -0,0 +1,19 @@ +--- +- name: Ensure virtualenv in {{ pretix_virtualenv_dir }} is present + ansible.builtin.pip: + name: "{{ pretix_virtualenv_packages }}" + state: "{{ pretix_virtualenv_state }}" + chdir: "{{ pretix_install_dir }}" + virtualenv: "{{ pretix_virtualenv_dir }}" + virtualenv_command: "{{ pretix_virtualenv_command }}" + virtualenv_site_packages: "{{ pretix_virtualenv_site_packages }}" + become: true + become_user: "{{ pretix_user }}" + +# TODO: determine to only do this on a) upgrades or b) initial deployis +- name: Ensure pretix static assets are built + ansible.builtin.command: + cmd: "{{ pretix_virtualenv_dir }}/bin/python -m pretix rebuild" + chdir: "{{ pretix_install_dir }}" + environment: + VIRTUAL_ENV: "{{ pretix_virtualenv_dir }}" diff --git a/roles/pretix/tasks/deploy.yml b/roles/pretix/tasks/deploy.yml new file mode 100644 index 0000000..e4b340c --- /dev/null +++ b/roles/pretix/tasks/deploy.yml @@ -0,0 +1,5 @@ +--- +- name: Ensure pretix is deployed using {{ pretix_deployment_method }} + ansible.builtin.include_tasks: + file: "deploy-{{ pretix_deployment_method }}.yml" + when: pretix_state == 'present' diff --git a/roles/pretix/tasks/main.yml b/roles/pretix/tasks/main.yml new file mode 100644 index 0000000..1cb4ea5 --- /dev/null +++ b/roles/pretix/tasks/main.yml @@ -0,0 +1,16 @@ +--- +- name: Ensure preconditions are met + ansible.builtin.include_tasks: + file: "check.yml" + +- name: Ensure deployment preparations are done + ansible.builtin.include_tasks: + file: "prepare.yml" + +- name: Ensure pretix is configured + ansible.builtin.include_tasks: + file: "configure.yml" + +- name: Ensure pretix is deployed + ansible.builtin.include_tasks: + file: "deploy.yml" diff --git a/roles/pretix/tasks/prepare-systemd.yml b/roles/pretix/tasks/prepare-systemd.yml new file mode 100644 index 0000000..dce21dd --- /dev/null +++ b/roles/pretix/tasks/prepare-systemd.yml @@ -0,0 +1,19 @@ +--- +- name: Ensure ansible facts are collected + ansible.builtin.setup: + gather_subset: + - "!all" + - "pkg_mgr" + - "distribution" + - "distribution_release" + - "distribution_version" + - "distribution_major_version" + +- name: Ensure system packages are present (apt) + ansible.builtin.apt: + name: "{{ package }}" + state: "{{ pretix_state }}" + loop: "{{ pretix_packages[ansible_distribution | lower][ansible_distribution_major_version] }}" + loop_control: + loop_var: "package" + when: ansible_facts['pkg_mgr'] == 'apt' diff --git a/roles/pretix/tasks/prepare.yml b/roles/pretix/tasks/prepare.yml new file mode 100644 index 0000000..3bea8cc --- /dev/null +++ b/roles/pretix/tasks/prepare.yml @@ -0,0 +1,29 @@ +--- +- name: Ensure pretix user '{{ pretix_user }}' is {{ pretix_state }} + ansible.builtin.user: + name: "{{ pretix_user }}" + state: "{{ pretix_state }}" + system: "{{ pretix_user_system }}" + create_home: "{{ pretix_user_create_home }}" + register: pretix_user_info + +- name: Ensure host directories are {{ pretix_state }} + ansible.builtin.file: + path: "{{ item.path }}" + owner: "{{ item.owner | default(pretix_user_id) }}" + group: "{{ item.group | default(pretix_group_id) }}" + mode: "{{ item.mode | default('0750') }}" + state: "directory" + loop: + - path: "{{ pretix_config_dir }}" + - path: "{{ pretix_virtualenv_dir }}" + - path: "{{ pretix_data_dir }}" + - path: "{{ pretix_media_dir }}" + when: pretix_state == 'present' + +- name: Ensure deployment-type specific preparations for '{{ pretix_deployment_method }}' are run + ansible.builtin.include_tasks: + file: "prepare-{{ pretix_deployment_method }}.yml" + when: + - pretix_state == 'present' + - pretix_deployment_method in ['systemd'] diff --git a/roles/pretix/templates/pretix.service.j2 b/roles/pretix/templates/pretix.service.j2 new file mode 100644 index 0000000..c4cfe08 --- /dev/null +++ b/roles/pretix/templates/pretix.service.j2 @@ -0,0 +1,16 @@ +[Unit] +Description={{ pretix_systemd_unit_description }} +After={{ pretix_systemd_unit_after }} + +[Service] +User={{ pretix_systemd_service_user }} +Group={{ pretix_systemd_service_group }} +{% for kv in pretix_systemd_service_environment | dict2items %} +Environment="{{ kv.key }}={{ kv.value }}" +{% endfor %} +WorkingDirectory={{ pretix_systemd_service_working_directory }} +ExecStart={{ pretix_systemd_service_exec_start }} +Restart={{ pretix_systemd_service_restart }} + +[Install] +WantedBy={{ pretix_systemd_install_wanted_by }} diff --git a/roles/pretix/vars/main.yml b/roles/pretix/vars/main.yml new file mode 100644 index 0000000..464f8aa --- /dev/null +++ b/roles/pretix/vars/main.yml @@ -0,0 +1,7 @@ +--- +pretix_states: + - "present" + - "absent" + +pretix_deployment_methods: + - "systemd"