diff --git a/CHANGELOG.md b/CHANGELOG.md index 5fea8b78..25d35138 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # 2023-02-17 +## Synapse templates customization support + +The playbook can now help you customize Synapse's templates. + +Additional details are available in the [Customizing templates](docs/configuring-playbook-synapse.md#customizing-templates) section of our Synapse documentation. + ## The matrix-redis role lives independently now **TLDR**: the `matrix-redis` role is now included from another repository. Some variables have been renamed. All functionality remains intact. diff --git a/docs/configuring-playbook-synapse.md b/docs/configuring-playbook-synapse.md index 4dc8f519..ef562ae8 100644 --- a/docs/configuring-playbook-synapse.md +++ b/docs/configuring-playbook-synapse.md @@ -80,3 +80,42 @@ matrix_synapse_configuration_extension_yaml: | backchannel_logout_enabled: true # Optional ``` + +## Customizing templates + +[Templates](https://github.com/matrix-org/synapse/blob/develop/docs/templates.md) are used by Synapse for showing **certain web pages** handled by the server, as well as for **email notifications**. + +This playbook allows you to customize the default templates (see the [`synapse/res/templates` directory](https://github.com/matrix-org/synapse/tree/develop/synapse/res/templates)). + +If template customization is enabled, the playbook will build a custom container image based on the official one. + +Your custom templates need to live in a public or private git repository. This repository will be cloned during Synapse image customization (during the playbook run). + +To enable template customizations, use a configuration (`inventory/host_vars/matrix.DOMAIN/vars.yml`) like this: + +```yaml +# If you'd like to ensure that the customized image is built each time the playbook runs, enable this. +# Otherwise, the customized image will only be rebuilt whenever the Synapse version changes (once every ~2 weeks). +# matrix_synapse_docker_image_customized_build_nocache: true + +matrix_synapse_container_image_customizations_templates_enabled: true + +# Our templates live in a templates/ directory within the repository. +# If they're at the root path, delete this line. +matrix_synapse_container_image_customizations_templates_in_container_template_files_relative_path: templates + +matrix_synapse_container_image_customizations_templates_git_repository_url: git@github.com:organization/repository.git +matrix_synapse_container_image_customizations_templates_git_repository_branch: main + +matrix_synapse_container_image_customizations_templates_git_repository_keyscan_enabled: true +matrix_synapse_container_image_customizations_templates_git_repository_keyscan_hostname: github.com + +# If your git repository is public, do not define the private key (remove the variable). +matrix_synapse_container_image_customizations_templates_git_repository_ssh_private_key: | + -----BEGIN OPENSSH PRIVATE KEY----- + .... + -----END OPENSSH PRIVATE KEY----- +``` + +As mentioned in Synapse's Templates documentation, Synapse will fall back to its own templates if a template is not found in that directory. +Due to this, it's recommended to only store and maintain template files in your repository if you need to make custom changes. Other files (which you don't need to change), should not be duplicated, so that you don't need to worry about getting out-of-sync with the original Synapse templates. diff --git a/roles/custom/matrix-synapse/defaults/main.yml b/roles/custom/matrix-synapse/defaults/main.yml index 9842f31f..e4e2e5e2 100644 --- a/roles/custom/matrix-synapse/defaults/main.yml +++ b/roles/custom/matrix-synapse/defaults/main.yml @@ -21,12 +21,41 @@ matrix_synapse_container_image_self_build_repo: "https://github.com/matrix-org/s # - `matrix_synapse_container_image_customizations_dockerfile_body_custom` # - `matrix_synapse_docker_image_customized` # - `matrix_synapse_docker_image_final` -matrix_synapse_container_image_customizations_enabled: "{{ matrix_synapse_ext_synapse_s3_storage_provider_enabled }}" +matrix_synapse_container_image_customizations_enabled: |- + {{ + matrix_synapse_container_image_customizations_s3_storage_provider_installation_enabled + or + matrix_synapse_container_image_customizations_templates_enabled + }} # Controls whether custom build steps will be added to the Dockerfile for installing s3-storage-provider. # The version that will be installed is specified in `matrix_synapse_ext_synapse_s3_storage_provider_version`. matrix_synapse_container_image_customizations_s3_storage_provider_installation_enabled: "{{ matrix_synapse_ext_synapse_s3_storage_provider_enabled }}" +# Controls whether custom build steps will be added to the Dockerfile for customizing the email templates used by Synapse. +# +# Example usage: +# +# ```yml +# matrix_synapse_container_image_customizations_templates_enabled: true +# # The templates are expected to be in a `templates/` subdirectory in +# matrix_synapse_container_image_customizations_templates_in_container_template_files_relative_path: templates/ +# matrix_synapse_container_image_customizations_templates_git_repository_url: git@github.com:organization/repository.git +# matrix_synapse_container_image_customizations_templates_git_repository_branch: main +# matrix_synapse_container_image_customizations_templates_git_repository_keyscan_enabled: true +# matrix_synapse_container_image_customizations_templates_git_repository_keyscan_hostname: github.com +# ``` +# +# See: https://github.com/matrix-org/synapse/blob/develop/docs/templates.md +matrix_synapse_container_image_customizations_templates_enabled: false +matrix_synapse_container_image_customizations_templates_in_container_base_path: /custom-templates +matrix_synapse_container_image_customizations_templates_in_container_template_files_relative_path: '' +matrix_synapse_container_image_customizations_templates_in_container_full_path: "{{ matrix_synapse_container_image_customizations_templates_in_container_base_path }}/{{ matrix_synapse_container_image_customizations_templates_in_container_template_files_relative_path }}" +matrix_synapse_container_image_customizations_templates_git_repository_url: '' +matrix_synapse_container_image_customizations_templates_git_repository_branch: main +matrix_synapse_container_image_customizations_templates_git_repository_keyscan_enabled: false +matrix_synapse_container_image_customizations_templates_git_repository_keyscan_hostname: '' + # matrix_synapse_container_image_customizations_dockerfile_body contains your custom Dockerfile steps # for building your customized Synapse image based on the original (upstream) image (`matrix_synapse_docker_image`). # A `FROM ...` clause is included automatically so you don't have to. @@ -49,6 +78,15 @@ matrix_synapse_docker_image_force_pull: "{{ matrix_synapse_docker_image.endswith # This image will be based on the upstream `matrix_synapse_docker_image` image, only if `matrix_synapse_container_image_customizations_enabled: true`. matrix_synapse_docker_image_customized: "localhost/matrixdotorg/synapse:{{ matrix_synapse_docker_image_tag }}-customized" +# Controls whether the customized image (`matrix_synapse_docker_image_customized`) is to be force-built without layer caching enabled. +# This is useful if you've enabled customizations (e.g. `matrix_synapse_container_image_customizations_templates_enabled`), +# which clone some branch of some repository, and you'd like for each Ansible run to pull new revisions from that branch. +matrix_synapse_docker_image_customized_build_nocache: false + +# Controls whether the customized image (`matrix_synapse_docker_image_customized`) is to be built, even if it already exists. +# Related to: matrix_synapse_docker_image_customized_build_nocache +matrix_synapse_docker_image_customized_force_source: "{{ matrix_synapse_docker_image_customized_build_nocache }}" + # matrix_synapse_docker_image_final holds the name of the Synapse image to run depending on whether or not customizations are enabled. matrix_synapse_docker_image_final: "{{ matrix_synapse_docker_image_customized if matrix_synapse_container_image_customizations_enabled else matrix_synapse_docker_image }} " @@ -230,6 +268,13 @@ matrix_synapse_rc_federation: matrix_synapse_federation_rr_transactions_per_room_per_second: 50 +# Controls the templates directory setting. +# +# See: +# - `matrix_synapse_container_image_customizations_templates_enabled` +# - https://github.com/matrix-org/synapse/blob/develop/docs/templates.md +matrix_synapse_templates_custom_template_directory: "{{ matrix_synapse_container_image_customizations_templates_in_container_full_path if matrix_synapse_container_image_customizations_templates_enabled else '' }}" + # Controls whether the TLS federation listener is enabled (tcp/8448). # Only makes sense if federation is enabled (`matrix_synapse_federation_enabled`). # Note that federation may potentially be enabled as non-TLS on `matrix_synapse_container_federation_api_plain_port` as well. diff --git a/roles/custom/matrix-synapse/tasks/synapse/setup_install.yml b/roles/custom/matrix-synapse/tasks/synapse/setup_install.yml index 7a7b5ed3..4a62d88d 100644 --- a/roles/custom/matrix-synapse/tasks/synapse/setup_install.yml +++ b/roles/custom/matrix-synapse/tasks/synapse/setup_install.yml @@ -76,10 +76,11 @@ community.docker.docker_image: name: "{{ matrix_synapse_docker_image_customized }}" source: build + force_source: "{{ matrix_synapse_docker_image_customized_force_source }}" build: dockerfile: Dockerfile path: "{{ matrix_synapse_customized_docker_src_files_path }}" - pull: true + nocache: "{{ matrix_synapse_docker_image_customized_build_nocache }}" - name: Check if a Synapse signing key exists ansible.builtin.stat: diff --git a/roles/custom/matrix-synapse/tasks/validate_config.yml b/roles/custom/matrix-synapse/tasks/validate_config.yml index 31a10e91..607c75b8 100644 --- a/roles/custom/matrix-synapse/tasks/validate_config.yml +++ b/roles/custom/matrix-synapse/tasks/validate_config.yml @@ -76,3 +76,22 @@ when: "item.old in matrix_synapse_configuration_extension" with_items: - {'old': 'federation_ip_range_blacklist', 'new': 'ip_range_blacklist'} + +- when: matrix_synapse_container_image_customizations_templates_enabled | bool + block: + - name: Fail if required `matrix_synapse_container_image_customizations_templates_*` settings not defined + ansible.builtin.fail: + msg: >- + You need to define a required configuration setting (`{{ item }}`) when enabling `matrix_synapse_container_image_customizations_templates_enabled`. + when: "vars[item] == ''" + with_items: + - matrix_synapse_container_image_customizations_templates_git_repository_url + - matrix_synapse_container_image_customizations_templates_git_repository_branch + + - name: Fail if required `matrix_synapse_container_image_customizations_templates_git_repository_keyscan_*` settings not defined + ansible.builtin.fail: + msg: >- + You need to define a required configuration setting (`{{ item }}`) when enabling `matrix_synapse_container_image_customizations_templates_git_repository_keyscan`. + when: "matrix_synapse_container_image_customizations_templates_git_repository_keyscan_enabled | bool and vars[item] == ''" + with_items: + - matrix_synapse_container_image_customizations_templates_git_repository_keyscan_hostname diff --git a/roles/custom/matrix-synapse/templates/synapse/customizations/Dockerfile.j2 b/roles/custom/matrix-synapse/templates/synapse/customizations/Dockerfile.j2 index 3919e955..6257f198 100644 --- a/roles/custom/matrix-synapse/templates/synapse/customizations/Dockerfile.j2 +++ b/roles/custom/matrix-synapse/templates/synapse/customizations/Dockerfile.j2 @@ -1,7 +1,51 @@ +#jinja2: lstrip_blocks: "True" FROM {{ matrix_synapse_docker_image }} {% if matrix_synapse_container_image_customizations_s3_storage_provider_installation_enabled %} RUN pip install synapse-s3-storage-provider=={{ matrix_synapse_ext_synapse_s3_storage_provider_version }} {% endif %} +{% if matrix_synapse_container_image_customizations_templates_enabled %} +{# +This ugly script below does quite a lot: + - installs git and other dependencies temporarily, just so we could do a shallow-clone + - prepare the SSH config: keyscanning (if enabled), private key (if enabled) + - performs a git shallow clone with just the branch we need + - makes sure the files are owned by the user that will actually run the container later + - removes the `.git` directory to save space, but keeps git revision in `git-revision.txt`, should we need it for debugging + - finally, verifies that the templates path can indeed be found within the base path (sanity check) +#} +{% set dependencies = ['git', 'ssh', 'openssh-client'] %} +RUN \ + {% if matrix_synapse_container_image_customizations_templates_git_repository_ssh_private_key %} + echo '{{ matrix_synapse_container_image_customizations_templates_git_repository_ssh_private_key | b64encode }}' | base64 -d > /custom-templates-private-key && \ + chmod 400 /custom-templates-private-key && \ + {% endif %} + apt-get update && \ + apt-get install --no-install-recommends -y {{ dependencies | join(' ') }} && \ + {% if matrix_synapse_container_image_customizations_templates_git_repository_keyscan_enabled %} + mkdir ~/.ssh && \ + chmod 700 ~/.ssh && \ + ssh-keyscan -t rsa {{ matrix_synapse_container_image_customizations_templates_git_repository_keyscan_hostname }} >> ~/.ssh/known_hosts && \ + {% endif %} + {% if matrix_synapse_container_image_customizations_templates_git_repository_ssh_private_key %}GIT_SSH_COMMAND='ssh -i /custom-templates-private-key'{% endif %} git \ + clone \ + --branch={{ matrix_synapse_container_image_customizations_templates_git_repository_branch }} \ + --depth=1 \ + --single-branch \ + --no-tags \ + {{ matrix_synapse_container_image_customizations_templates_git_repository_url }} \ + {{ matrix_synapse_container_image_customizations_templates_in_container_base_path }} && \ + /bin/sh -c 'cd {{ matrix_synapse_container_image_customizations_templates_in_container_base_path }} && git rev-parse HEAD > git-revision.txt' && \ + rm -rf {{ matrix_synapse_container_image_customizations_templates_in_container_base_path }}/.git && \ + chown -R {{ matrix_synapse_uid }}:{{ matrix_synapse_gid }} {{ matrix_synapse_container_image_customizations_templates_in_container_base_path }} && \ + apt-get autoremove -y {{ dependencies | join(' ') }} && \ + {% if matrix_synapse_container_image_customizations_templates_git_repository_ssh_private_key %} + rm /custom-templates-private-key && \ + {% endif %} + true + +RUN /bin/sh -c 'stat {{ matrix_synapse_container_image_customizations_templates_in_container_base_path }}/{{ matrix_synapse_container_image_customizations_templates_in_container_template_files_relative_path }} || exit 1' +{% endif %} + {{ matrix_synapse_container_image_customizations_dockerfile_body_custom }} diff --git a/roles/custom/matrix-synapse/templates/synapse/homeserver.yaml.j2 b/roles/custom/matrix-synapse/templates/synapse/homeserver.yaml.j2 index 1afbcdc3..9b039ff5 100644 --- a/roles/custom/matrix-synapse/templates/synapse/homeserver.yaml.j2 +++ b/roles/custom/matrix-synapse/templates/synapse/homeserver.yaml.j2 @@ -555,6 +555,9 @@ templates: # information about using custom templates. # #custom_template_directory: /path/to/custom/templates/ + {% if matrix_synapse_templates_custom_template_directory %} + custom_template_directory: {{ matrix_synapse_templates_custom_template_directory | to_json }} + {% endif %} # List of rooms to exclude from sync responses. This is useful for server # administrators wishing to group users into a room without these users being able