Add Sygnal support

Fixes https://github.com/spantaleev/matrix-docker-ansible-deploy/issues/683
This commit is contained in:
Slavi Pantaleev
2021-03-20 13:31:34 +02:00
parent 54315505de
commit 9a0222fa47
20 changed files with 797 additions and 0 deletions

View File

@ -0,0 +1,95 @@
# Sygnal is a reference Push Gateway for Matrix.
# To make use of it for delivering push notificatins, you'll need to develop/build your own Matrix app.
# Learn more here: https://github.com/matrix-org/sygnal
matrix_sygnal_enabled: false
matrix_sygnal_base_path: "{{ matrix_base_data_path }}/sygnal"
matrix_sygnal_config_path: "{{ matrix_sygnal_base_path }}/config"
matrix_sygnal_data_path: "{{ matrix_sygnal_base_path }}/data"
matrix_sygnal_version: v0.9.0
matrix_sygnal_docker_image: "docker.io/matrixdotorg/sygnal:{{ matrix_sygnal_version }}"
matrix_sygnal_docker_image_force_pull: "{{ matrix_sygnal_docker_image.endswith(':latest') }}"
# List of systemd services that matrix-sygnal.service depends on.
matrix_sygnal_systemd_required_services_list: ['docker.service']
# List of systemd services that matrix-sygnal.service wants
matrix_sygnal_systemd_wanted_services_list: []
# Controls whether the matrix-sygnal container exposes its HTTP port (tcp/6000 in the container).
#
# Takes an "<ip>:<port>" or "<port>" value (e.g. "127.0.0.1:6000"), or empty string to not expose.
matrix_sygnal_container_http_host_bind_port: ''
# A list of extra arguments to pass to the container
matrix_sygnal_container_extra_arguments: []
# Database-related configuration fields.
#
# To use SQLite, stick to these defaults.
#
# To use Postgres:
# - change the engine (`matrix_sygnal_database_engine: 'postgres'`)
# - adjust your database credentials via the `matrix_sygnal_postgres_*` variables
matrix_sygnal_database_engine: 'sqlite'
matrix_sygnal_sqlite_database_path_local: "{{ matrix_sygnal_data_path }}/sygnal.db"
matrix_sygnal_sqlite_database_path_in_container: "/data/sygnal.db"
matrix_sygnal_database_username: 'matrix_sygnal'
matrix_sygnal_database_password: 'some-password'
matrix_sygnal_database_hostname: 'matrix-postgres'
matrix_sygnal_database_port: 5432
matrix_sygnal_database_name: 'matrix_sygnal'
matrix_sygnal_database_connection_string: 'postgres://{{ matrix_sygnal_database_username }}:{{ matrix_sygnal_database_password }}@{{ matrix_sygnal_database_hostname }}:{{ matrix_sygnal_database_port }}/{{ matrix_sygnal_database_name }}'
# A map (dictionary) of apps instances that this server works with.
#
# Example configuration:
#
# matrix_sygnal_apps:
# com.example.myapp.ios:
# type: apns
# # .. more configuration ..
# com.example.myapp.android:
# type: gcm
# api_key: your_api_key_for_gcm
# # .. more configuration ..
#
# The APNS configuration needs to reference some certificate files.
# One can put these in the `matrix_sygnal_data_path` directory (`/matrix/sygnal/data`), mounted to `/data` in the container.
# The `matrix_sygnal_apps` paths need to use the in-container path (`/data`).
# To install these files via the playbook, one can use the `matrix-aux` role.
# Examples and more details are available in `docs/configuring-playbook-sygnal.md`.
matrix_sygnal_apps: []
matrix_sygnal_metrics_prometheus_enabled: false
# Default Sygnal configuration template which covers the generic use case.
# You can customize it by controlling the various variables inside it.
#
# For a more advanced customization, you can extend the default (see `matrix_sygnal_configuration_extension_yaml`)
# or completely replace this variable with your own template.
matrix_sygnal_configuration_yaml: "{{ lookup('template', 'templates/sygnal.yaml.j2') }}"
matrix_sygnal_configuration_extension_yaml: |
# Your custom YAML configuration for Sygnal goes here.
# This configuration extends the default starting configuration (`matrix_sygnal_configuration_yaml`).
#
# You can override individual variables from the default configuration, or introduce new ones.
#
# If you need something more special, you can take full control by
# completely redefining `matrix_sygnal_configuration_yaml`.
#
# Example configuration extension follows:
# metrics:
# opentracing:
# enabled: true
matrix_sygnal_configuration_extension: "{{ matrix_sygnal_configuration_extension_yaml|from_yaml if matrix_sygnal_configuration_extension_yaml|from_yaml is mapping else {} }}"
# Holds the final sygnal configuration (a combination of the default and its extension).
# You most likely don't need to touch this variable. Instead, see `matrix_sygnal_configuration_yaml`.
matrix_sygnal_configuration: "{{ matrix_sygnal_configuration_yaml|from_yaml|combine(matrix_sygnal_configuration_extension, recursive=True) }}"

View File

@ -0,0 +1,3 @@
- set_fact:
matrix_systemd_services_list: "{{ matrix_systemd_services_list + ['matrix-sygnal.service'] }}"
when: matrix_sygnal_enabled|bool

View File

@ -0,0 +1,21 @@
- import_tasks: "{{ role_path }}/tasks/init.yml"
tags:
- always
- import_tasks: "{{ role_path }}/tasks/validate_config.yml"
when: run_setup|bool
tags:
- setup-all
- setup-sygnal
- import_tasks: "{{ role_path }}/tasks/setup_install.yml"
when: run_setup|bool and matrix_sygnal_enabled|bool
tags:
- setup-all
- setup-sygnal
- import_tasks: "{{ role_path }}/tasks/setup_uninstall.yml"
when: run_setup|bool and not matrix_sygnal_enabled|bool
tags:
- setup-all
- setup-sygnal

View File

@ -0,0 +1,73 @@
---
- set_fact:
matrix_sygnal_requires_restart: false
- block:
- name: Check if an SQLite database already exists
stat:
path: "{{ matrix_sygnal_sqlite_database_path_local }}"
register: matrix_sygnal_sqlite_database_path_local_stat_result
- block:
- set_fact:
matrix_postgres_db_migration_request:
src: "{{ matrix_sygnal_sqlite_database_path_local }}"
dst: "{{ matrix_sygnal_database_connection_string }}"
caller: "{{ role_path|basename }}"
engine_variable_name: 'matrix_sygnal_database_engine'
engine_old: 'sqlite'
systemd_services_to_stop: ['matrix-sygnal.service']
pgloader_options: ['--with "quote identifiers"']
- import_tasks: "{{ role_path }}/../matrix-postgres/tasks/util/migrate_db_to_postgres.yml"
- set_fact:
matrix_sygnal_requires_restart: true
when: "matrix_sygnal_sqlite_database_path_local_stat_result.stat.exists|bool"
when: "matrix_sygnal_database_engine == 'postgres'"
- name: Ensure Sygnal image is pulled
docker_image:
name: "{{ matrix_sygnal_docker_image }}"
source: "{{ 'pull' if ansible_version.major > 2 or ansible_version.minor > 7 else omit }}"
force_source: "{{ matrix_sygnal_docker_image_force_pull if ansible_version.major > 2 or ansible_version.minor >= 8 else omit }}"
force: "{{ omit if ansible_version.major > 2 or ansible_version.minor >= 8 else matrix_sygnal_docker_image_force_pull }}"
- name: Ensure Sygnal paths exists
file:
path: "{{ item }}"
state: directory
mode: 0750
owner: "{{ matrix_user_username }}"
group: "{{ matrix_user_groupname }}"
with_items:
- "{{ matrix_sygnal_base_path }}"
- "{{ matrix_sygnal_config_path }}"
- "{{ matrix_sygnal_data_path }}"
- name: Ensure Sygnal config installed
copy:
content: "{{ matrix_sygnal_configuration|to_nice_yaml }}"
dest: "{{ matrix_sygnal_config_path }}/sygnal.yaml"
mode: 0640
owner: "{{ matrix_user_username }}"
group: "{{ matrix_user_groupname }}"
- name: Ensure matrix-sygnal.service installed
template:
src: "{{ role_path }}/templates/systemd/matrix-sygnal.service.j2"
dest: "{{ matrix_systemd_path }}/matrix-sygnal.service"
mode: 0644
register: matrix_sygnal_systemd_service_result
- name: Ensure systemd reloaded after matrix-sygnal.service installation
service:
daemon_reload: yes
when: "matrix_sygnal_systemd_service_result.changed|bool"
- name: Ensure matrix-sygnal.service restarted, if necessary
service:
name: "matrix-sygnal.service"
state: restarted
when: "matrix_sygnal_requires_restart|bool"

View File

@ -0,0 +1,35 @@
---
- name: Check existence of matrix-sygnal service
stat:
path: "{{ matrix_systemd_path }}/matrix-sygnal.service"
register: matrix_sygnal_service_stat
- name: Ensure matrix-sygnal is stopped
service:
name: matrix-sygnal
state: stopped
daemon_reload: yes
register: stopping_result
when: "matrix_sygnal_service_stat.stat.exists|bool"
- name: Ensure matrix-sygnal.service doesn't exist
file:
path: "{{ matrix_systemd_path }}/matrix-sygnal.service"
state: absent
when: "matrix_sygnal_service_stat.stat.exists|bool"
- name: Ensure systemd reloaded after matrix-sygnal.service removal
service:
daemon_reload: yes
when: "matrix_sygnal_service_stat.stat.exists|bool"
- name: Ensure Sygnal base directory doesn't exist
file:
path: "{{ matrix_sygnal_base_path }}"
state: absent
- name: Ensure Sygnal Docker image doesn't exist
docker_image:
name: "{{ matrix_sygnal_docker_image }}"
state: absent

View File

@ -0,0 +1,7 @@
- name: Fail if no Sygnal apps defined
fail:
msg: >-
Enabling Sygnal requires that you specify at least one app in `matrix_sygnal_apps`
with_items:
- "matrix_sygnal_access_token"
when: "matrix_sygnal_enabled and matrix_sygnal_apps|length == 0"

View File

@ -0,0 +1,288 @@
##
# This is a configuration for Sygnal, the reference Push Gateway for Matrix
# See: matrix.org
##
# The 'database' setting defines the database that sygnal uses to store all of
# its data.
#
# 'name' gives the database engine to use: either 'sqlite3' (for SQLite) or
# 'psycopg2' (for PostgreSQL).
#
# 'args' gives options which are passed through to the database engine,
# except for options starting 'cp_', which are used to configure the Twisted
# connection pool. For a reference to valid arguments, see:
# * for sqlite: https://docs.python.org/3/library/sqlite3.html#sqlite3.connect
# * for postgres: https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PARAMKEYWORDS
# * for the connection pool: https://twistedmatrix.com/documents/current/api/twisted.enterprise.adbapi.ConnectionPool.html#__init__
#
#
# Example SQLite configuration:
#
#database:
# name: sqlite3
# args:
# dbfile: /path/to/database.db
#
#
# Example Postgres configuration:
#
#database:
# name: psycopg2
# args:
# host: localhost
# database: sygnal
# user: sygnal
# password: pass
# cp_min: 1
# cp_max: 5
#
{% if matrix_sygnal_database_engine == 'sqlite' %}
database:
name: sqlite3
args:
dbfile: {{ matrix_sygnal_sqlite_database_path_in_container|to_json }}
{% else %}
database:
name: psycopg2
args:
host: {{ matrix_sygnal_database_hostname|to_json }}
database: {{ matrix_sygnal_database_name|to_json }}
user: {{ matrix_sygnal_database_username|to_json }}
password: {{ matrix_sygnal_database_password|to_json }}
cp_min: 1
cp_max: 5
{% endif %}
## Logging #
#
log:
# Specify a Python logging 'dictConfig', as described at:
# https://docs.python.org/3.7/library/logging.config.html#logging.config.dictConfig
#
setup:
version: 1
formatters:
normal:
format: "%(asctime)s [%(process)d] %(levelname)-5s %(name)s %(message)s"
handlers:
# This handler prints to Standard Error
#
stderr:
class: "logging.StreamHandler"
formatter: "normal"
stream: "ext://sys.stderr"
# This handler prints to Standard Output.
#
stdout:
class: "logging.StreamHandler"
formatter: "normal"
stream: "ext://sys.stdout"
# This handler demonstrates logging to a text file on the filesystem.
# You can use logrotate(8) to perform log rotation.
#
#file:
# class: "logging.handlers.WatchedFileHandler"
# formatter: "normal"
# filename: "./sygnal.log"
loggers:
# sygnal.access contains the access logging lines.
# Comment out this section if you don't want to give access logging
# any special treatment.
#
sygnal.access:
propagate: false
handlers: ["stdout"]
level: "INFO"
# sygnal contains log lines from Sygnal itself.
# You can comment out this section to fall back to the root logger.
#
sygnal:
propagate: false
handlers: ["stderr"]
root:
# Specify the handler(s) to send log messages to.
handlers: ["stderr"]
level: "INFO"
disable_existing_loggers: false
access:
# Specify whether or not to trust the IP address in the `X-Forwarded-For`
# header. In general, you want to enable this if and only if you are using a
# reverse proxy which is configured to emit it.
#
x_forwarded_for: true
## HTTP Server (Matrix Push Gateway API) #
#
http:
# Specify a list of interface addresses to bind to.
#
# This example listens on the IPv4 loopback device:
#bind_addresses: ['127.0.0.1']
# This example listens on all IPv4 interfaces:
#bind_addresses: ['0.0.0.0']
# This example listens on all IPv4 and IPv6 interfaces:
#bind_addresses: ['0.0.0.0', '::']
bind_addresses: ['::']
# Specify the port number to listen on.
#
port: 6000
## Proxying for outgoing connections #
#
# Specify the URL of a proxy to use for outgoing traffic
# (e.g. to Apple & Google) if desired.
# Currently only HTTP proxies with CONNECT capability are supported.
#
# If you do not specify a value, the `HTTPS_PROXY` environment variable will
# be used if present. Otherwise, no proxy will be used.
#
# Default is unspecified.
#
#proxy: 'http://user:secret@prox:8080'
## Metrics #
#
metrics:
## Prometheus #
#
prometheus:
# Specify whether or not to enable Prometheus.
#
enabled: false
# Specify an address for the Prometheus HTTP Server to listen on.
#
address: '0.0.0.0'
# Specify a port for the Prometheus HTTP Server to listen on.
#
port: 8000
## OpenTracing #
#
opentracing:
# Specify whether or not to enable OpenTracing.
#
enabled: false
# Specify an implementation of OpenTracing to use. Currently only 'jaeger'
# is supported.
#
implementation: jaeger
# Specify the service name to be reported to the tracer.
#
service_name: sygnal
# Specify configuration values to pass to jaeger_client.
#
jaeger:
sampler:
type: 'const'
param: 1
# local_agent:
# reporting_host: '127.0.0.1'
# reporting_port:
logging: true
## Sentry #
#
sentry:
# Specify whether or not to enable Sentry.
#
enabled: false
# Specify your Sentry DSN if you enable Sentry
#
#dsn: "https://<key>@sentry.example.org/<project>"
## Pushkins/Apps #
#
# Add a section for every push application here.
# Specify the pushkey for the application and also the type.
# For the type, you may specify a fully-qualified Python classname if desired.
#
#apps:
# This is an example APNs push configuration
#
#com.example.myapp.ios:
# type: apns
#
# # Authentication
# #
# # Two methods of authentication to APNs are currently supported.
# #
# # You can authenticate using a key:
# keyfile: my_key.p8
# key_id: MY_KEY_ID
# team_id: MY_TEAM_ID
# topic: MY_TOPIC
#
# # Or, a certificate can be used instead:
# certfile: com.example.myApp_prod_APNS.pem
#
# # This is the maximum number of in-flight requests *for this pushkin*
# # before additional notifications will be failed.
# # (This is a robustness measure to prevent one pushkin stacking up with
# # queued requests and saturating the inbound connection queue of a load
# # balancer or reverse proxy).
# # Defaults to 512 if unset.
# #
# #inflight_request_limit: 512
#
# # Specifies whether to use the production or sandbox APNs server. Note that
# # sandbox tokens should only be used with the sandbox server and vice versa.
# #
# # Valid options are:
# # * production
# # * sandbox
# #
# # The default is 'production'. Uncomment to use the sandbox instance.
# #platform: sandbox
# This is an example GCM/FCM push configuration.
#
#com.example.myapp.android:
# type: gcm
# api_key: your_api_key_for_gcm
#
# # This is the maximum number of connections to GCM servers at any one time
# # the default is 20.
# #max_connections: 20
#
# # This is the maximum number of in-flight requests *for this pushkin*
# # before additional notifications will be failed.
# # (This is a robustness measure to prevent one pushkin stacking up with
# # queued requests and saturating the inbound connection queue of a load
# # balancer or reverse proxy).
# # Defaults to 512 if unset.
# #
# #inflight_request_limit: 512
#
# # This allows you to specify additional options to send to Firebase.
# #
# # Of particular interest, admins who wish to support iOS apps using Firebase
# # probably wish to set content_available, and may need to set mutable_content.
# # (content_available allows your iOS app to be woken up by data messages,
# # and mutable_content allows your notification to be modified by a
# # Notification Service app extension).
# #
# # See https://firebase.google.com/docs/cloud-messaging/http-server-ref
# # for the exhaustive list of valid options.
# #
# # Do not specify `data`, `priority`, `to` or `registration_ids` as they may
# # be overwritten or lead to an invalid request.
# #
# #fcm_options:
# # content_available: true
# # mutable_content: true
apps: {{ matrix_sygnal_apps|to_json }}

View File

@ -0,0 +1,42 @@
#jinja2: lstrip_blocks: "True"
[Unit]
Description=Matrix Sygnal
{% for service in matrix_sygnal_systemd_required_services_list %}
Requires={{ service }}
After={{ service }}
{% endfor %}
{% for service in matrix_sygnal_systemd_wanted_services_list %}
Wants={{ service }}
{% endfor %}
DefaultDependencies=no
[Service]
Type=simple
Environment="HOME={{ matrix_systemd_unit_home_path }}"
ExecStartPre=-{{ matrix_host_command_sh }} -c '{{ matrix_host_command_docker }} kill matrix-sygnal 2>/dev/null'
ExecStartPre=-{{ matrix_host_command_sh }} -c '{{ matrix_host_command_docker }} rm matrix-sygnal 2>/dev/null'
ExecStart={{ matrix_host_command_docker }} run --rm --name matrix-sygnal \
--log-driver=none \
--user={{ matrix_user_uid }}:{{ matrix_user_gid }} \
--cap-drop=ALL \
--env=SYGNAL_CONF=/config/sygnal.yaml \
--network={{ matrix_docker_network }} \
{% if matrix_sygnal_container_http_host_bind_port %}
-p {{ matrix_sygnal_container_http_host_bind_port }}:6000 \
{% endif %}
--mount type=bind,src={{ matrix_sygnal_config_path }},dst=/config \
--mount type=bind,src={{ matrix_sygnal_data_path }},dst=/data \
{% for arg in matrix_sygnal_container_extra_arguments %}
{{ arg }} \
{% endfor %}
{{ matrix_sygnal_docker_image }}
ExecStop=-{{ matrix_host_command_sh }} -c '{{ matrix_host_command_docker }} kill matrix-sygnal 2>/dev/null'
ExecStop=-{{ matrix_host_command_sh }} -c '{{ matrix_host_command_docker }} rm matrix-sygnal 2>/dev/null'
Restart=always
RestartSec=30
SyslogIdentifier=matrix-sygnal
[Install]
WantedBy=multi-user.target