From 5df89a44b386cfba65310742e3e2f4f6bd0cd6fe Mon Sep 17 00:00:00 2001 From: Slavi Pantaleev Date: Fri, 17 Feb 2023 19:37:34 +0200 Subject: [PATCH] Add support for customizing Synapse templates --- CHANGELOG.md | 6 +++ docs/configuring-playbook-synapse.md | 39 +++++++++++++++ roles/custom/matrix-synapse/defaults/main.yml | 47 ++++++++++++++++++- .../tasks/synapse/setup_install.yml | 3 +- .../matrix-synapse/tasks/validate_config.yml | 19 ++++++++ .../synapse/customizations/Dockerfile.j2 | 44 +++++++++++++++++ .../templates/synapse/homeserver.yaml.j2 | 3 ++ 7 files changed, 159 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5fea8b789..25d351387 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 4dc8f5195..ef562ae88 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 9842f31f1..e4e2e5e2a 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 7a7b5ed37..4a62d88d9 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 31a10e918..607c75b8c 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 3919e9557..6257f1985 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 1afbcdc37..9b039ff52 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