Compare commits
19 Commits
eccc308bcf
...
79f1be5cbe
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79f1be5cbe | ||
|
|
98edd6051a | ||
|
|
b74b49d6e9 | ||
|
|
d7c806bf19 | ||
|
|
1b62d4df72 | ||
|
|
b17932816b | ||
|
|
563bfa5a32 | ||
|
|
ab4b6b7825 | ||
|
|
64606707d4 | ||
|
|
cb3d5f177d | ||
|
|
61a8e67205 | ||
|
|
61aa99bcd1 | ||
|
|
2287077f42 | ||
|
|
007514feb5 | ||
|
|
28dc77a907 | ||
|
|
356560f268 | ||
|
|
93cc64ba98 | ||
|
|
5648887a64 | ||
|
|
e7dab881f2 |
@@ -49,10 +49,20 @@ argument_specs:
|
||||
type: str
|
||||
required: true
|
||||
readonly:
|
||||
description: If true, volume will be mounted as read only inside the container
|
||||
description: If true, mount will be read only inside the container
|
||||
type: bool
|
||||
required: false
|
||||
default: false
|
||||
user:
|
||||
description: Volume owner uid. Only applicable if mount type is volume.
|
||||
type: str
|
||||
required: false
|
||||
default: ""
|
||||
group:
|
||||
description: Volume owner gid. Only applicable if mount type is volume.
|
||||
type: str
|
||||
required: false
|
||||
default: ""
|
||||
|
||||
container_publish_ports:
|
||||
description: "A list of published ports in docker format (<host listen address>:<host port>:<container port>)"
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
---
|
||||
- name: Validate inputs
|
||||
ansible.builtin.import_tasks: validation.yaml
|
||||
|
||||
- name: Create networks for container {{ container_name }}
|
||||
ansible.builtin.include_role:
|
||||
name: network
|
||||
@@ -8,16 +11,37 @@
|
||||
loop_control:
|
||||
loop_var: network
|
||||
|
||||
- name: Create volumes for container {{ container_name }}
|
||||
ansible.builtin.include_role:
|
||||
name: volume
|
||||
vars:
|
||||
volume_name: "{{ volume.source }}"
|
||||
volume_uid: "{{ volume.user | default('') }}"
|
||||
volume_gid: "{{ volume.group | default('') }}"
|
||||
loop: "{{ _container_volumes }}"
|
||||
loop_control:
|
||||
loop_var: volume
|
||||
|
||||
- name: Create secrets for container {{ container_name }}
|
||||
containers.podman.podman_secret:
|
||||
name: "{{ item.name }}"
|
||||
data: "{{ item.value | default(lookup('community.general.random_string', special=false, length=128)) }}"
|
||||
skip_existing: "{{ item.value is not defined }}"
|
||||
no_log: true
|
||||
loop: "{{ container_secrets }}"
|
||||
|
||||
- name: Create container service {{ container_name }}
|
||||
ansible.builtin.template:
|
||||
src: container.j2
|
||||
dest: "/etc/containers/systemd/{{ container_name }}.container"
|
||||
mode: "0600"
|
||||
containers.podman.podman_container:
|
||||
image: "{{ container_image }}"
|
||||
name: "{{ container_name }}"
|
||||
command: "{{ container_command or omit }}"
|
||||
user: "{{ container_user or omit }}"
|
||||
mount: "{{ _container_mounts | map('items') | map('map', 'join', '=') | map('join', ',') }}"
|
||||
network: "{{ container_networks | map('regex_replace', '$', '.network') }}"
|
||||
publish: "{{ container_publish_ports }}"
|
||||
secrets: "{{ container_secrets | map(attribute='name') }}"
|
||||
env: "{{ container_env.keys() | zip(container_env.values() | map('quote')) | community.general.dict }}"
|
||||
state: quadlet
|
||||
quadlet_file_mode: "0600"
|
||||
quadlet_options: "{{ _container_quadlet_options }}"
|
||||
notify: "Restart container service {{ container_name }}"
|
||||
|
||||
8
roles/container/tasks/validation.yaml
Normal file
8
roles/container/tasks/validation.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
- name: Assert mount sources and destinations are unique
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- _container_mount_destinations | unique | length == _container_mount_destinations | length
|
||||
- _container_mount_sources | unique | length == _container_mount_sources | length
|
||||
fail_msg: "Container mount sources and destinations must be unique. Failed with mounts: {{ container_mounts }}"
|
||||
quiet: true
|
||||
@@ -1,49 +0,0 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
[Unit]
|
||||
Description=Container {{ container_name }}
|
||||
{% for requirement in container_requires %}
|
||||
Requires={{ requirement }}
|
||||
After={{ requirement }}
|
||||
{% endfor %}
|
||||
{% for want in container_wants %}
|
||||
Requires={{ want }}
|
||||
Before={{ want }}
|
||||
{% endfor %}
|
||||
|
||||
[Container]
|
||||
Image={{ container_image }}
|
||||
ContainerName={{ container_name }}
|
||||
{% if container_command | length > 0 %}
|
||||
Exec="{{ container_command | join('" "') }}"
|
||||
{% endif %}
|
||||
{% if container_user | length > 0 %}
|
||||
User={{ container_user }}
|
||||
{% endif %}
|
||||
{% for mount in container_mounts %}
|
||||
Mount={% for key, value in mount.items() %}{{ key }}={{ value }}{% if not loop.last %},{% endif %}{% endfor %}
|
||||
|
||||
{% endfor %}
|
||||
{% for network in container_networks %}
|
||||
Network={{ network }}.network
|
||||
{% endfor %}
|
||||
{% for port in container_publish_ports %}
|
||||
PublishPort={{ port }}
|
||||
{% endfor %}
|
||||
{% for secret in container_secrets %}
|
||||
Secret={{ secret.name }}
|
||||
{% endfor %}
|
||||
{% for key, value in container_env.items() %}
|
||||
Environment={{ key }}={{ value }}
|
||||
{% endfor %}
|
||||
{% if container_auto_update %}
|
||||
AutoUpdate=registry
|
||||
{% endif %}
|
||||
|
||||
{% if container_auto_start %}
|
||||
[Service]
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
{% endif %}
|
||||
45
roles/container/vars/main.yaml
Normal file
45
roles/container/vars/main.yaml
Normal file
@@ -0,0 +1,45 @@
|
||||
---
|
||||
_container_volumes: "{{ container_mounts | selectattr('type', '==', 'volume') }}"
|
||||
|
||||
_container_mount_sources: "{{ container_mounts | map(attribute='source') }}"
|
||||
_container_mount_destinations: "{{ container_mounts | map(attribute='destination') }}"
|
||||
|
||||
_container_volume_mount_sources: >-
|
||||
{{
|
||||
_container_volumes
|
||||
| map(attribute='source')
|
||||
| map('regex_replace', '$', '.volume')
|
||||
| map('community.general.dict_kv', 'source')
|
||||
}}
|
||||
|
||||
_container_mounts: >-
|
||||
{{
|
||||
container_mounts | selectattr('type', '!=', 'volume') +
|
||||
container_mounts | selectattr('type', '==', 'volume')
|
||||
| community.general.remove_keys(['user', 'group'])
|
||||
| zip(_container_volume_mount_sources) | map('combine')
|
||||
}}
|
||||
|
||||
_container_quadlet_unit_options: |
|
||||
[Unit]
|
||||
Description=Container {{ container_name }}
|
||||
StartLimitIntervalSec=30
|
||||
StartLimitBurst=3
|
||||
{% for requirement in container_requires %}
|
||||
Requires={{ requirement }}
|
||||
After={{ requirement }}
|
||||
{% endfor %}
|
||||
{% for want in container_wants %}
|
||||
Wants={{ want }}
|
||||
{% endfor %}
|
||||
_container_quadlet_auto_start_options: |
|
||||
[Service]
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
_container_quadlet_options_incl_empty:
|
||||
- "{{ 'AutoUpdate=registry' if container_auto_update else '' }}"
|
||||
- "{{ _container_quadlet_unit_options }}"
|
||||
- "{{ _container_quadlet_auto_start_options if container_auto_start else '' }}"
|
||||
_container_quadlet_options: "{{ _container_quadlet_options_incl_empty | select('!=', '') }}"
|
||||
@@ -18,6 +18,8 @@
|
||||
readonly: true
|
||||
service_container_http_port: 8080
|
||||
service_domains: "{{ example_domains }}"
|
||||
service_database_type: postgres
|
||||
service_postgres_tag: 16-alpine
|
||||
service_container_publish_ports:
|
||||
- "127.0.0.1:8080:8080"
|
||||
- "0.0.0.0:4443:8043"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
- name: "Create container network service {{ network_name }}"
|
||||
ansible.builtin.template:
|
||||
src: network.j2
|
||||
dest: "/etc/containers/systemd/{{ network_name }}.network"
|
||||
mode: "0644"
|
||||
containers.podman.podman_network:
|
||||
name: "{{ network_name }}"
|
||||
state: quadlet
|
||||
quadlet_file_mode: "0644"
|
||||
notify: Reload systemd daemon
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
[Unit]
|
||||
Description=Container network {{ network_name }}
|
||||
|
||||
[Network]
|
||||
NetworkName={{ network_name }}
|
||||
@@ -12,5 +12,7 @@
|
||||
|
||||
- name: Install podman
|
||||
ansible.builtin.apt:
|
||||
name: podman
|
||||
name:
|
||||
- podman
|
||||
- aardvark-dns
|
||||
tags: podman
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
---
|
||||
service_domains: []
|
||||
|
||||
service_container_user: ""
|
||||
service_container_publish_ports: []
|
||||
service_container_mounts: []
|
||||
service_container_secrets: []
|
||||
service_container_env: {}
|
||||
|
||||
service_database_type: none
|
||||
|
||||
@@ -25,6 +25,11 @@ argument_specs:
|
||||
description: "The image to run in the service container(s), in FQIN format (registry/imagename:tag)."
|
||||
type: str
|
||||
required: true
|
||||
service_container_user:
|
||||
description: The UID to run as inside the container
|
||||
type: str
|
||||
required: false
|
||||
default: ""
|
||||
service_container_publish_ports:
|
||||
description: "A list of published ports in docker format (<host listen address>:<host port>:<container port>)"
|
||||
type: list
|
||||
@@ -45,11 +50,13 @@ argument_specs:
|
||||
choices:
|
||||
- volume
|
||||
- bind
|
||||
- template
|
||||
source:
|
||||
description:
|
||||
- Mount source.
|
||||
- If mount type is volume, name of the volume.
|
||||
- If mount type is bind, host path to bind mount inside the container.
|
||||
- If mount type is template, the name of the template file, must end in .j2
|
||||
type: str
|
||||
required: true
|
||||
destination:
|
||||
@@ -57,10 +64,38 @@ argument_specs:
|
||||
type: str
|
||||
required: true
|
||||
readonly:
|
||||
description: If true, volume will be mounted as read only inside the container
|
||||
description:
|
||||
- If true, volume will be mounted as read only inside the container.
|
||||
- Defaults to false for volume and bind, true for template
|
||||
type: bool
|
||||
required: false
|
||||
default: false
|
||||
user:
|
||||
description: Volume owner uid. Only applicable if mount type is volume.
|
||||
type: str
|
||||
required: false
|
||||
default: ""
|
||||
group:
|
||||
description: Volume owner gid. Only applicable if mount type is volume.
|
||||
type: str
|
||||
required: false
|
||||
default: ""
|
||||
service_container_secrets:
|
||||
description: A list of secrets available to the service container in /run/secrets/<service name>-<secret name>
|
||||
type: list
|
||||
required: false
|
||||
default: []
|
||||
elements: dict
|
||||
options:
|
||||
name:
|
||||
description: Name of the secret
|
||||
type: str
|
||||
required: true
|
||||
value:
|
||||
description:
|
||||
- Value of the secret. Defaults to a 128-character random string containing alphanumeric characters.
|
||||
- If the value is not explicitly set, it will not be changed if the secret already exists.
|
||||
type: str
|
||||
required: false
|
||||
service_container_env:
|
||||
description: A dict of environment variables for the service container(s)
|
||||
type: dict
|
||||
@@ -123,11 +158,13 @@ argument_specs:
|
||||
choices:
|
||||
- volume
|
||||
- bind
|
||||
- template
|
||||
source:
|
||||
description:
|
||||
- Mount source.
|
||||
- If mount type is volume, name of the volume.
|
||||
- If mount type is bind, host path to bind mount inside the container.
|
||||
- If mount type is template, the name of the template file, must end in .j2
|
||||
type: str
|
||||
required: true
|
||||
destination:
|
||||
@@ -135,10 +172,11 @@ argument_specs:
|
||||
type: str
|
||||
required: true
|
||||
readonly:
|
||||
description: If true, volume will be mounted as read only inside the container
|
||||
description:
|
||||
- If true, volume will be mounted as read only inside the container
|
||||
- Defaults to false for volume and bind, true for template
|
||||
type: bool
|
||||
required: false
|
||||
default: false
|
||||
publish_ports:
|
||||
description: "A list of published ports in docker format (<host listen address>:<host port>:<container port>)"
|
||||
type: list
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
- name: Set database name
|
||||
ansible.builtin.set_fact:
|
||||
_service_database_name: "{{ service_name }}-{{ service_database_type }}"
|
||||
- name: Include database variables
|
||||
ansible.builtin.include_vars:
|
||||
file: database.yaml
|
||||
|
||||
- name: Database container for {{ service_name }}
|
||||
ansible.builtin.include_role:
|
||||
@@ -20,6 +20,7 @@
|
||||
container_env:
|
||||
POSTGRES_USER: "{{ service_name | replace('-', '_') }}"
|
||||
POSTGRES_PASSWORD_FILE: "/run/secrets/{{ _service_database_name }}"
|
||||
POSTGRES_INITDB_ARGS: "--encoding=UTF-8 --lc-collate=C --lc-ctype=C"
|
||||
container_auto_update: "{{ service_auto_update }}"
|
||||
|
||||
- name: Get database secret info
|
||||
|
||||
@@ -7,24 +7,26 @@
|
||||
_service_container_mounts: []
|
||||
_service_container_requires: "{{ service_requires }}"
|
||||
|
||||
- name: Mounts for {{ service_name }}
|
||||
ansible.builtin.include_tasks: mounts.yaml
|
||||
when: service_container_mounts | length > 0
|
||||
|
||||
- name: Databse for {{ service_name }}
|
||||
ansible.builtin.include_tasks: database.yaml
|
||||
when: "service_database_type != 'none'"
|
||||
|
||||
- name: Mounts for {{ service_name }}
|
||||
ansible.builtin.include_tasks: mounts.yaml
|
||||
when: service_container_mounts | length > 0
|
||||
|
||||
- name: Main container for {{ service_name }}
|
||||
ansible.builtin.include_role:
|
||||
ansible.builtin.import_role:
|
||||
name: container
|
||||
vars:
|
||||
container_name: "{{ service_name }}"
|
||||
container_image: "{{ service_container_image }}"
|
||||
container_user: "{{ service_container_user }}"
|
||||
container_mounts: "{{ _service_container_mounts }}"
|
||||
container_publish_ports: "{{ service_container_publish_ports }}"
|
||||
container_networks:
|
||||
- "{{ service_name }}"
|
||||
container_secrets: "{{ _service_container_secrets }}"
|
||||
container_env: "{{ service_container_env }}"
|
||||
container_requires: "{{ _service_container_requires }}"
|
||||
container_wants: "{{ [service_name + '-socat.socket'] if service_domains | length > 0 else [] }}"
|
||||
|
||||
32
roles/service/tasks/mount.yaml
Normal file
32
roles/service/tasks/mount.yaml
Normal file
@@ -0,0 +1,32 @@
|
||||
---
|
||||
- name: Set container named mounts
|
||||
ansible.builtin.set_fact:
|
||||
_service_container_mounts: >
|
||||
{{ _service_container_mounts +
|
||||
[mount | combine({'source': service_name + '-' + mount.source})] }}
|
||||
when: mount.type == 'volume'
|
||||
|
||||
- name: Set container named mounts
|
||||
ansible.builtin.set_fact:
|
||||
_service_container_mounts: "{{ _service_container_mounts + [mount] }}"
|
||||
when: mount.type == 'bind'
|
||||
|
||||
- name: Template mounts
|
||||
when: mount.type == 'template'
|
||||
block:
|
||||
- name: Set template host path
|
||||
ansible.builtin.set_fact:
|
||||
_service_template_host_path: "{{ _service_host_directory }}/mounts/{{ (mount.source | split('.'))[0:-1] | join('.') }}" # Strip .j2 extension
|
||||
|
||||
- name: Template files for template mounts
|
||||
ansible.builtin.template:
|
||||
src: "{{ mount.source }}"
|
||||
dest: "{{ _service_template_host_path }}"
|
||||
mode: "0644"
|
||||
notify: "Restart container service {{ service_name }}"
|
||||
|
||||
- name: Set container template mounts
|
||||
ansible.builtin.set_fact:
|
||||
_service_container_mounts: >
|
||||
{{ _service_container_mounts +
|
||||
[{'readonly': true} | combine(mount) | combine({'type': 'bind', 'source': _service_template_host_path})] }}
|
||||
@@ -1,18 +1,21 @@
|
||||
---
|
||||
- name: Set container named mounts
|
||||
ansible.builtin.set_fact:
|
||||
_service_container_mounts: >
|
||||
{{ _service_container_mounts +
|
||||
[mount | combine({'source': service_name + '-' + mount.source})] }}
|
||||
when: mount.type == 'volume'
|
||||
loop: "{{ service_container_mounts }}"
|
||||
loop_control:
|
||||
loop_var: mount
|
||||
- name: Create template mount directories under /srv
|
||||
when: _service_template_mounts | length > 0
|
||||
block:
|
||||
- name: Create directory {{ _service_host_directory }}
|
||||
ansible.builtin.file:
|
||||
path: "{{ _service_host_directory }}"
|
||||
state: directory
|
||||
mode: "0755"
|
||||
|
||||
- name: Set container named mounts
|
||||
ansible.builtin.set_fact:
|
||||
_service_container_mounts: "{{ _service_container_mounts + [mount] }}"
|
||||
when: mount.type == 'bind'
|
||||
- name: Create directory {{ _service_host_directory + '/mounts' }}
|
||||
ansible.builtin.file:
|
||||
path: "{{ _service_host_directory }}/mounts"
|
||||
state: directory
|
||||
mode: "0700"
|
||||
|
||||
- name: Set mount definitions for {{ service_name }}
|
||||
ansible.builtin.include_tasks: mount.yaml
|
||||
loop: "{{ service_container_mounts }}"
|
||||
loop_control:
|
||||
loop_var: mount
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
---
|
||||
- name: Fail if service_container_user is not string
|
||||
ansible.builtin.fail:
|
||||
msg: "service_container_user must be a string, not int."
|
||||
when: service_container_user is not string
|
||||
|
||||
- name: Fail if service_database_type is postgres but service_postgres_tag is not set
|
||||
ansible.builtin.fail:
|
||||
msg: "service_postgres_tag needs to be set when database type is postgres"
|
||||
when: "service_database_type == 'postgres' and service_postgres_tag is not defined"
|
||||
|
||||
- name: Fail if template mount source doesn't end in .j2
|
||||
ansible.builtin.fail:
|
||||
msg: "Template mount source file name needs to end in .j2. The file {{ item.source }} of {{ service_name }} doesn't."
|
||||
when: "item.source | split('.') | last != 'j2'"
|
||||
loop: "{{ _service_template_mounts }}"
|
||||
|
||||
2
roles/service/vars/database.yaml
Normal file
2
roles/service/vars/database.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
---
|
||||
_service_database_name: "{{ service_name }}-{{ service_database_type }}"
|
||||
14
roles/service/vars/main.yaml
Normal file
14
roles/service/vars/main.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
_service_template_mounts: "{{ service_container_mounts | selectattr('type', '==', 'template') | list }}"
|
||||
_service_host_directory: "/srv/{{ service_name }}"
|
||||
|
||||
_service_container_secrets: >
|
||||
{{
|
||||
service_container_secrets
|
||||
| zip(service_container_secrets
|
||||
| map(attribute='name')
|
||||
| map('regex_replace', '^', service_name ~ '-')
|
||||
| map('community.general.dict_kv', 'name')
|
||||
)
|
||||
| map('combine')
|
||||
}}
|
||||
2
roles/synapse/README.md
Normal file
2
roles/synapse/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
Sets up a matrix synapse podman container.
|
||||
See https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html for info on configuration options where descriptions are not provided in this documentation.
|
||||
18
roles/synapse/defaults/main.yaml
Normal file
18
roles/synapse/defaults/main.yaml
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
synapse_postgres_tag: 16-alpine
|
||||
|
||||
synapse_trusted_key_servers:
|
||||
- matrix.org
|
||||
|
||||
synapse_room_complexity_limit: 0
|
||||
synapse_room_complexity_error: ""
|
||||
|
||||
synapse_turn_uris: []
|
||||
|
||||
synapse_max_upload_size: 50M
|
||||
synapse_allow_public_rooms_over_federation: false
|
||||
synapse_auto_accept_invites:
|
||||
enabled: false
|
||||
synapse_auto_join_rooms: []
|
||||
|
||||
synapse_smtp_server: ""
|
||||
87
roles/synapse/meta/argument_specs.yaml
Normal file
87
roles/synapse/meta/argument_specs.yaml
Normal file
@@ -0,0 +1,87 @@
|
||||
---
|
||||
argument_specs:
|
||||
main:
|
||||
description:
|
||||
- Sets up a matrix synapse podman container.
|
||||
- >-
|
||||
See https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html for info on configuration options where descriptions are
|
||||
not provided in this documentation.
|
||||
options:
|
||||
synapse_server_name:
|
||||
description: Matrix server name. This can not be changed without a full reset and database wipe. This will be visible to users.
|
||||
type: str
|
||||
required: true
|
||||
synapse_external_domain:
|
||||
description:
|
||||
- The public-facing domain that clients use to access synapse, without https://. e.g. matrix.domain.tld
|
||||
- This is used to set the public_baseurl option for synapse (with https:// and trailing / added)
|
||||
type: str
|
||||
required: true
|
||||
synapse_signing_key:
|
||||
description: The homeserver signing key
|
||||
type: str
|
||||
required: true
|
||||
synapse_trusted_key_servers:
|
||||
type: list
|
||||
required: false
|
||||
default:
|
||||
- matrix.org
|
||||
elements: str
|
||||
synapse_remote_room_complexity_limit:
|
||||
description: Sets limit_remote_rooms.complexity value
|
||||
type: float
|
||||
required: false
|
||||
default: 0
|
||||
synapse_room_complexity_error:
|
||||
description: Sets limit_remote_rooms.copmlexity_error value. Required if synapse_remote_room_complexity_level is set.
|
||||
type: str
|
||||
default: ""
|
||||
synapse_turn_uris:
|
||||
type: list
|
||||
required: false
|
||||
default: []
|
||||
elements: str
|
||||
synapse_turn_shared_secret:
|
||||
description: Required if synapse_turn_uris is not empty
|
||||
type: str
|
||||
synapse_email_smtp_server:
|
||||
description: email.smtp_host, set this to enable sending emails
|
||||
type: str
|
||||
required: false
|
||||
default: ""
|
||||
synapse_email_smtp_user:
|
||||
description: Required if synapse_email_smtp_server is set
|
||||
type: str
|
||||
synapse_email_smtp_password:
|
||||
description: Required if synapse_email_smtp_server is set
|
||||
type: str
|
||||
synapse_email_from:
|
||||
description: Required if synapse_email_smtp_server is set
|
||||
type: str
|
||||
synapse_email_app_name:
|
||||
description: Required if synapse_email_smtp_server is set
|
||||
type: str
|
||||
synapse_max_upload_size:
|
||||
type: str
|
||||
required: false
|
||||
default: 50M
|
||||
synapse_allow_public_rooms_over_federation:
|
||||
type: bool
|
||||
required: false
|
||||
default: false
|
||||
synapse_auto_accept_invites:
|
||||
type: dict
|
||||
required: false
|
||||
default:
|
||||
enabled: false
|
||||
synapse_auto_join_rooms:
|
||||
type: list
|
||||
required: false
|
||||
default: []
|
||||
elements: str
|
||||
|
||||
synapse_postgres_tag:
|
||||
description: Postgres tag to use for synapse postgres container
|
||||
type: str
|
||||
required: false
|
||||
default: 16-alpine
|
||||
42
roles/synapse/tasks/main.yaml
Normal file
42
roles/synapse/tasks/main.yaml
Normal file
@@ -0,0 +1,42 @@
|
||||
---
|
||||
- name: Assert complexity error is set if complexity limit is
|
||||
ansible.builtin.assert:
|
||||
that: synapse_room_complexity_limit == 0 or synapse_room_complexity_error | length > 0
|
||||
fail_msg: "synapse_room_complexity_error must be set when synapse_room_complexity_limit is"
|
||||
quiet: true
|
||||
- name: Assert turn shared secret is set if turn uris is
|
||||
ansible.builtin.assert:
|
||||
that: synapse_turn_uris | length == 0 or synapse_turn_shared_secret | length > 0
|
||||
fail_msg: "synapse_turn_shared_secret must be set when synapse_turn_uris is"
|
||||
quiet: true
|
||||
|
||||
- name: Synapse container
|
||||
ansible.builtin.include_role:
|
||||
name: service
|
||||
vars:
|
||||
service_name: synapse
|
||||
service_container_image: "{{ _synapse_image_name }}"
|
||||
service_database_type: postgres
|
||||
service_postgres_tag: "{{ synapse_postgres_tag }}"
|
||||
service_container_mounts:
|
||||
- type: template
|
||||
source: homeserver.yaml.j2
|
||||
destination: /data/homeserver.yaml
|
||||
- type: template
|
||||
source: log.yaml.j2
|
||||
destination: /data/log.yaml
|
||||
- type: volume
|
||||
source: media
|
||||
destination: /data/media
|
||||
user: "991"
|
||||
group: "991"
|
||||
service_container_secrets:
|
||||
- name: signing-key
|
||||
value: "{{ synapse_signing_key }}"
|
||||
service_container_env:
|
||||
SYNAPSE_SERVER_NAME: "{{ synapse_server_name }}"
|
||||
SYNAPSE_REPORT_STATS: "no"
|
||||
UID: 991
|
||||
GID: 991
|
||||
service_container_http_port: 8008
|
||||
service_domains: "{{ [synapse_external_domain] }}"
|
||||
99
roles/synapse/templates/homeserver.yaml.j2
Normal file
99
roles/synapse/templates/homeserver.yaml.j2
Normal file
@@ -0,0 +1,99 @@
|
||||
---
|
||||
# vim:ft=yaml
|
||||
# {{ ansible_managed }}
|
||||
|
||||
signing_key_path: /run/secrets/synapse-signing-key
|
||||
media_store_path: /data/media
|
||||
log_config: /data/log.yaml
|
||||
|
||||
server_name: {{ synapse_server_name }}
|
||||
public_baseurl: https://{{ synapse_external_domain }}/
|
||||
report_stats: false
|
||||
|
||||
listeners:
|
||||
- port: 8008
|
||||
tls: false
|
||||
type: http
|
||||
x_forwarded: true
|
||||
resources:
|
||||
- names: [client, federation]
|
||||
|
||||
database:
|
||||
name: psycopg2
|
||||
args:
|
||||
host: synapse-postgres
|
||||
user: synapse
|
||||
password: "{{ _service_database_password }}"
|
||||
dbname: synapse
|
||||
|
||||
caches:
|
||||
global_factor: 1.0
|
||||
|
||||
enable_registration: false
|
||||
enable_3pid_changes: false
|
||||
ui_auth:
|
||||
session_timeout: 5m
|
||||
|
||||
trusted_key_servers:
|
||||
{% for server in synapse_trusted_key_servers %}
|
||||
- server_name: {{ server }}
|
||||
{% endfor %}
|
||||
suppress_key_server_warning: true
|
||||
|
||||
max_upload_sixe: "{{ synapse_max_upload_size }}"
|
||||
|
||||
{% if synapse_room_complexity_limit > 0 %}
|
||||
limit_remote_rooms:
|
||||
enabled: true
|
||||
complexity: {{ synapse_room_complexity_limit }}
|
||||
complexity_error: "{{ synapse_room_complexity_error }}"
|
||||
{% endif %}
|
||||
|
||||
url_preview_enabled: true
|
||||
url_preview_ip_range_blacklist:
|
||||
- '127.0.0.0/8'
|
||||
- '10.0.0.0/8'
|
||||
- '172.16.0.0/12'
|
||||
- '192.168.0.0/16'
|
||||
- '100.64.0.0/10'
|
||||
- '192.0.0.0/24'
|
||||
- '169.254.0.0/16'
|
||||
- '192.88.99.0/24'
|
||||
- '198.18.0.0/15'
|
||||
- '192.0.2.0/24'
|
||||
- '198.51.100.0/24'
|
||||
- '203.0.113.0/24'
|
||||
- '224.0.0.0/4'
|
||||
- '::1/128'
|
||||
- 'fe80::/10'
|
||||
- 'fc00::/7'
|
||||
- '2001:db8::/32'
|
||||
- 'ff00::/8'
|
||||
- 'fec0::/10'
|
||||
|
||||
turn_uris: {{ synapse_turn_uris }}
|
||||
{% if synapse_turn_uris | length > 0 %}
|
||||
turn_shared_secret: {{ synapse_turn_shared_secret }}
|
||||
{% endif %}
|
||||
turn_user_lifetime: 1d
|
||||
turn_allow_guests: false
|
||||
|
||||
{% if synapse_smtp_server | length > 0 %}
|
||||
email:
|
||||
smtp_host: {{ synapse_smtp_server }}
|
||||
smtp_port: 587
|
||||
smtp_user: {{ synapse_smtp_user }}
|
||||
smtp_pass: {{ synapse_smtp_password }}
|
||||
require_transport_security: true
|
||||
|
||||
notif_from: "{{ synapse_email_from }}"
|
||||
app_name: "{{ synapse_email_app_name }}"
|
||||
enable_notifs: true
|
||||
notif_for_new_users: false
|
||||
notif_delay_before_mail: 1h
|
||||
{% endif %}
|
||||
|
||||
allow_public_rooms_over_federation: {{ synapse_allow_public_rooms_over_federation }}
|
||||
auto_accept_invites: {{ synapse_auto_accept_invites }}
|
||||
auto_join_rooms: {{ synapse_auto_join_rooms }}
|
||||
autocreate_auto_join_rooms: false
|
||||
24
roles/synapse/templates/log.yaml.j2
Normal file
24
roles/synapse/templates/log.yaml.j2
Normal file
@@ -0,0 +1,24 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
version: 1
|
||||
|
||||
formatters:
|
||||
precise:
|
||||
format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s'
|
||||
|
||||
handlers:
|
||||
console:
|
||||
class: logging.StreamHandler
|
||||
formatter: precise
|
||||
|
||||
loggers:
|
||||
synapse:
|
||||
level: WARNING
|
||||
synapse.storage.SQL:
|
||||
level: WARNING
|
||||
|
||||
root:
|
||||
level: WARNING
|
||||
handlers: [console]
|
||||
|
||||
disable_existing_loggers: false
|
||||
2
roles/synapse/vars/main.yaml
Normal file
2
roles/synapse/vars/main.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
---
|
||||
_synapse_image_name: ghcr.io/element-hq/synapse:latest
|
||||
1
roles/volume/README.md
Normal file
1
roles/volume/README.md
Normal file
@@ -0,0 +1 @@
|
||||
Sets up podman volume with systemd unit (quadlet)
|
||||
3
roles/volume/defaults/main.yaml
Normal file
3
roles/volume/defaults/main.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
---
|
||||
volume_uid: ""
|
||||
volume_gid: ""
|
||||
19
roles/volume/meta/argument_specs.yaml
Normal file
19
roles/volume/meta/argument_specs.yaml
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
argument_specs:
|
||||
main:
|
||||
description: Sets up podman volume with systemd unit (quadlet)
|
||||
options:
|
||||
volume_name:
|
||||
description: Name of the volume. Must be unique within a host.
|
||||
type: str
|
||||
required: true
|
||||
volume_uid:
|
||||
description: Volume uid (the volume owner)
|
||||
type: str
|
||||
required: false
|
||||
default: ""
|
||||
volume_gid:
|
||||
description: Volume gid (the volume owner)
|
||||
type: str
|
||||
required: false
|
||||
default: ""
|
||||
3
roles/volume/meta/main.yaml
Normal file
3
roles/volume/meta/main.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
---
|
||||
dependencies:
|
||||
- role: podman
|
||||
11
roles/volume/tasks/main.yaml
Normal file
11
roles/volume/tasks/main.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
- name: Validate inputs
|
||||
ansible.builtin.import_tasks: validation.yaml
|
||||
|
||||
- name: Create container volume service {{ volume_name }}
|
||||
containers.podman.podman_volume:
|
||||
name: "{{ volume_name }}"
|
||||
options: "{{ volume_options }}"
|
||||
state: quadlet
|
||||
quadlet_file_mode: "0644"
|
||||
notify: Reload systemd daemon
|
||||
7
roles/volume/tasks/validation.yaml
Normal file
7
roles/volume/tasks/validation.yaml
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
- name: Assert volume_uid and volume_gid are strings
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- volume_uid is string
|
||||
- volume_gid is string
|
||||
fail_msg: "volume_uid and volume_gid must be strings, not int."
|
||||
6
roles/volume/vars/main.yaml
Normal file
6
roles/volume/vars/main.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
volume_mount_options_incl_empty:
|
||||
- "{{ 'uid=' ~ volume_uid if volume_uid | length > 0 else '' }}"
|
||||
- "{{ 'gid=' ~ volume_gid if volume_gid | length > 0 else '' }}"
|
||||
volume_mount_options: "{{ volume_mount_options_incl_empty | select('!=', '') | list }}"
|
||||
volume_options: "{{ ['o=' ~ volume_mount_options | join(',')] if volume_mount_options | length > 0 else [] }}"
|
||||
Reference in New Issue
Block a user