Compare commits

...

23 Commits

Author SHA1 Message Date
uumas
df7662e835 Add Euro-Office role 2026-09-22 04:33:13 +03:00
uumas
3ce5f94e87 v0.1.3 2026-09-21 05:54:01 +03:00
uumas
2d34f7a163 Add mautrix-whatsapp role 2026-09-21 05:53:00 +03:00
uumas
d6518d404e synapse: Add support for appservices and use secrets better 2026-09-21 05:51:48 +03:00
uumas
bb9026bb6a service: Template file improvements 2026-09-21 05:51:32 +03:00
uumas
e980ee0bfc nextcloud: Use correct user for AppAPI handlers 2026-09-19 15:47:56 +03:00
uumas
43f10d744a service: Allow templated files to be mounted as full directory 2026-08-04 20:15:54 +03:00
uumas
11e22ed34a service: Support connecting containers to tailscale network 2026-08-04 05:00:34 +03:00
uumas
ffa970eced container: Support referring to container files by network name 2026-08-02 04:49:27 +03:00
uumas
59fa9c0b36 synapse: Update MAS configuration 2026-07-22 07:37:06 +03:00
uumas
df302cf6f5 Add headscale 2026-06-08 19:36:46 +03:00
uumas
e28a4097a0 container, service: Support reloading containers on template file change 2026-06-08 19:11:16 +03:00
uumas
3e84073f39 service: Support validating templated files 2026-06-08 17:30:07 +03:00
uumas
40357a17ad service: Support udp port mappings 2026-06-08 17:29:44 +03:00
uumas
284ad35406 windmill, caddy_socket_proxy: Add readmes 2026-06-08 15:09:15 +03:00
uumas
63272d0d2f service: Fix redis volume name 2026-06-05 18:24:06 +03:00
uumas
f5735d39d3 windmill: fix native workers 2026-04-19 13:47:43 +03:00
uumas
792cf4ef39 synapse: Fix caddy path 2026-04-19 13:47:25 +03:00
uumas
c4256847c9 service: Allow specifying container hostname 2026-04-19 13:47:10 +03:00
uumas
c2fd6236fe service: samll improvements 2026-03-28 06:05:37 +02:00
uumas
edb803f3c1 nextcloud: Add support for additional networks 2026-03-28 06:04:48 +02:00
uumas
500bba84b4 windmill: Run worker outside of pinp 2026-03-26 04:11:50 +02:00
uumas
351ef2c5d4 service: Allow additional dependencies for additional containers 2026-03-26 04:06:26 +02:00
53 changed files with 1050 additions and 190 deletions

View File

@@ -3,7 +3,7 @@ namespace: uumas
name: podman
description: Roles for installing services in podman containers
readme: README.md
version: 0.1.1
version: 0.1.4
repository: "https://git.uumas.fi/uumas/ansible-podman"
license_file: LICENSE
authors:

View File

@@ -0,0 +1 @@
Sets up a caddy container and a systemd socket unit, forwarding traffic from it to target container

View File

@@ -14,3 +14,4 @@ container_auto_update: true
container_requires: []
container_wants: []
container_add_capabilities: []
container_reload_method: none

View File

@@ -4,3 +4,9 @@
systemd_restart_units: "{{ systemd_restart_units + [container_name ~ '.service'] }}" # noqa: var-naming[no-role-prefix]
changed_when: true
notify: Apply systemd unit restarts
- name: Reload container service {{ container_name }}
ansible.builtin.systemd_service:
name: "{{ container_name }}.service"
state: reloaded
when: "container_name ~ '.service' not in systemd_restart_units"

View File

@@ -212,3 +212,21 @@ argument_specs:
type: bool
required: false
default: true
container_reload_method:
description: |
How to reload configuration when systemctl reload is called
kill: Sends SIGHUP to the container
command: Runs the specified command inside the container
type: str
required: false
default: none
choices:
- kill
- command
- none
container_reload_command:
description: >-
Command to run inside container when systemctl reload is called.
Required if container_reload_method is command, ignored otherwise.
type: str
required: false

View File

@@ -16,7 +16,9 @@
network_name: "{{ network.name }}"
network_subnet: "{{ _container_network_subnet }}"
network_range: "{{ _container_network_range }}"
when: network_created_networks is not defined or network.name not in network_created_networks
when:
- "'.' not in network.name"
- network_created_networks is not defined or network.name not in network_created_networks
loop: "{{ container_networks }}"
loop_control:
loop_var: network

View File

@@ -69,6 +69,10 @@ _container_labels: >-
else {}
}}
_container_reload_commands:
kill: podman kill --signal HUP {{ container_name }}
command: podman exec {{ container_name }} {{ container_reload_command }}
_container_quadlet_unit_options: |
[Unit]
Description=Container {{ container_name }}
@@ -90,8 +94,12 @@ _container_quadlet_auto_start_options: |
[Install]
WantedBy=multi-user.target
_container_quadlet_reload_options: |
[Service]
ExecReload={{ _container_reload_commands[container_reload_method] }}
_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_reload_options if container_reload_method != 'none' else '' }}"
_container_quadlet_options: "{{ _container_quadlet_options_incl_empty | select('!=', '') }}"

View File

@@ -3,7 +3,7 @@ _container_networks: >-
{{
container_networks
| map(attribute='name')
| map('regex_replace', '$', '.network')
| map('regex_replace', '^(?!.*\.)(.*)$', '\1.network')
| zip(container_networks | map(attribute='ip', default=''))
| map('reject', 'equalto', '')
| map('join', ':ip=')

View File

@@ -0,0 +1 @@
Sets up a Euro Office podman container.

View File

@@ -0,0 +1,14 @@
---
argument_specs:
main:
description: Sets up a Euro Office podman container.
options:
euro_office_domains:
description: A list of domains the container should listen on.
type: list
required: true
elements: str
euro_office_jwt_secret:
description: JWT secret, must be at least 32 characters long
type: str
required: true

View File

@@ -0,0 +1,31 @@
---
- name: Euro-Office service
ansible.builtin.import_role:
name: service
vars:
service_name: euro-office
service_container_image: ghcr.io/euro-office/documentserver:latest
service_container_mounts:
- type: volume
source: data
destination: /var/lib/euro-office/documentserver
- type: volume
source: private
destination: /var/www/euro-office/Data
service_container_http_port: 80
service_domains: "{{ euro_office_domains }}"
service_database_type: postgres
service_database_secret_type: env
service_database_secret_target: DB_PWD
service_redis: true
service_container_secrets:
- name: jwt
type: env
target: JWT_SECRET
value: "{{ euro_office_jwt_secret }}"
service_container_env:
DB_HOST: postgres
DB_USER: euro_office
DB_NAME: euro_office
DB_PASSWORD__FILE: /run/secrets/postgres
REDIS_SERVER_HOST: redis

View File

@@ -0,0 +1 @@
Sets up a headscale container

View File

@@ -0,0 +1,4 @@
---
headscale_oidc_issuer_url: ""
headscale_oidc_client_id: ""
headscale_oidc_client_secret: ""

View File

@@ -0,0 +1,85 @@
---
argument_specs:
main:
description: "Sets up a headscale container"
options:
headscale_domain:
description: Domain headscale should be available at
type: str
required: true
headscale_magicdns_base_domain:
description: Base domain for magic dns hostnames
type: str
required: true
headscale_policy:
description:
- Headscale policy configuration.
- See https://headscale.net/stable/ref/acls/
- This role's support for acls is currently quite limited. Waiting for headscale to release grants support.
type: dict
required: true
options:
groups:
description: >-
Groups of users. Formatted as dict where dict key is group name and
value is a list of users in the group.
type: dict
required: false
hosts:
description: Mapping of host names to ip addresses
type: dict
required: false
tagOwners:
description: Mapping of tags to lists of their owners
type: dict
required: false
acls:
description: List of acls
type: list
required: true
elements: dict
options:
action:
description: ACL action
type: str
required: true
choices:
- accept
- check
src:
description: >-
A list of sources, formatted as prefix:name:ports,
where prefix is the type of object, like tag: or group:,
name is the object name and ports is a comma separated list of ports or *
type: list
required: true
elements: str
dst:
description: A list of destinations. Same format as sources.
type: list
required: true
elements: str
proto:
description: Protocol
type: str
required: false
choices:
- tcp
- udp
- icmp
headscale_oidc_issuer_url:
description: OIDC issuer url. Leave unset to not use OIDC.
type: str
required: false
default: ""
headscale_oidc_client_id:
description: OIDC client id. Required if OIDC issuer is set.
type: str
required: false
default: ""
headscale_oidc_client_secret:
description: OIDC client secret. Required if OIDC issuer is set.
type: str
required: false
default: ""

View File

@@ -0,0 +1,36 @@
---
- name: Headscale service
ansible.builtin.import_role:
name: service
vars:
service_name: headscale
service_container_image: docker.io/headscale/headscale:stable
service_container_command: serve
service_container_mounts:
- type: volume
source: data
destination: /var/lib/headscale
- type: template
source: config.yaml.j2
destination: /etc/headscale/config.yaml
- type: template
source: policy.hujson.j2
destination: /etc/headscale/policy.hujson
template_validate_command: headscale policy check --file /etc/headscale/policy.hujson
service_container_http_port: 8080
service_domains:
- "{{ headscale_domain }}"
service_container_publish_ports:
- name: stun
container_port: 3478
protocol: udp
host_port: 3478
service_container_secrets: "{{ _headscale_secrets }}"
service_container_reload_method: kill
- name: Open port for stun
ansible.posix.firewalld:
service: stun
state: enabled
permanent: true
immediate: true

View File

@@ -0,0 +1,56 @@
---
# vim:ft=yaml
# {{ ansible_managed }}
listen_addr: 0.0.0.0:8080
server_url: https://{{ headscale_domain }}
noise:
private_key_path: /var/lib/headscale/noise_private.key
prefixes:
v4: 100.64.0.0/10
v6: fd7a:115c:a1e0::/48
allocation: sequential
derp:
server:
enabled: true
region_id: 999
region_code: "headscale"
region_name: "Headscale embedded DERP"
verify_clients: true
stun_listen_addr: "0.0.0.0:3478"
private_key_path: /var/lib/headscale/derp_server_private.key
urls: []
database:
type: sqlite
sqlite:
path: /var/lib/headscale/db.sqlite
policy:
mode: file
path: /etc/headscale/policy.hujson
dns:
magic_dns: true
base_domain: {{ headscale_magicdns_base_domain }}
nameservers:
global:
- https://dns.quad9.net/dns-query
logtail:
enabled: false
{% if headscale_oidc_issuer_url | length > 0 %}
oidc:
only_start_if_oidc_is_available: false
issuer: {{ headscale_oidc_issuer_url }}
client_id: "{{ headscale_oidc_client_id }}"
client_secret_path: /run/secrets/oidc-client-secret
pkce:
enabled: true
{% endif %}

View File

@@ -0,0 +1,3 @@
// {{ ansible_managed }}
{{ headscale_policy | to_nice_json }}

View File

@@ -0,0 +1,6 @@
---
_headscale_oidc_secret:
name: oidc-client-secret
value: "{{ headscale_oidc_client_secret }}"
_headscale_secrets: "{{ [_headscale_oidc_secret] if headscale_oidc_issuer_url | length > 0 else [] }}"

View File

@@ -46,11 +46,6 @@ passwords:
algorithm: argon2id
minimum_complexity: 3
clients:
- client_id: 0000000000000000000SYNAPSE
client_auth_method: client_secret_basic
client_secret: "{{ matrix_authentication_service_client_secret }}"
matrix:
homeserver: {{ matrix_authentication_service_homeserver_name }}
secret: "{{ matrix_authentication_service_homeserver_secret }}"

View File

@@ -0,0 +1 @@
Sets up a mautrix-whatsapp bridge

View File

@@ -0,0 +1,5 @@
---
mautrix_whatsapp_os_name: Matrix bridge
mautrix_whatsapp_bot_displayname: WhatsApp bridge
mautrix_whatsapp_default_relays: []
mautrix_whatsapp_permissions: {}

View File

@@ -0,0 +1,57 @@
---
argument_specs:
main:
description:
- Sets up a mautrix-whatsapp bridge
options:
mautrix_whatsapp_homeserver_name:
description: Matrix server name of homeserver the bridge is connected to.
type: str
required: true
mautrix_whatsapp_as_token:
description: A secret token that the application service will use to authenticate requests to the homeserver
type: str
required: true
mautrix_whatsapp_hs_token:
description: A secret token that the homeserver will use authenticate requests to the application service
type: str
required: true
mautrix_whatsapp_doublepuppet_token:
description: Double puppeting as token to impersonate matrix users
type: str
required: true
mautrix_whatsapp_os_name:
description: Device name that's shown in the "WhatsApp Web" section in the mobile app
type: str
required: false
default: Matrix bridge
mautrix_whatsapp_bot_displayname:
description: Display name for the bridge bot
type: str
required: false
default: WhatsApp bridge
mautrix_whatsapp_default_relays:
description: List of user login IDs which anyone can set as a relay, as long as the relay user is in the room
type: list
required: false
default: []
elements: str
mautrix_whatsapp_permissions:
description: Permissions for using the bridge. All users are given the relay permission regardless of this.
type: list
required: false
default: []
elements: dict
options:
key:
description: Domain or user id to apply permission value to
type: str
required: true
value:
description: Permission value to apply
type: str
required: true
choices:
- commands
- user
- admin

View File

@@ -0,0 +1,32 @@
---
- name: Mautrix-WhatsApp container
ansible.builtin.import_role:
name: service
vars:
service_name: mautrix-whatsapp
service_container_image: "{{ _mautrix_whatsapp_image }}"
service_container_user: 1337:1337
service_container_command:
- /usr/bin/mautrix-whatsapp
- --no-update
service_database_type: postgres
service_container_additional_networks:
- synapse-mautrix-whatsapp
service_container_mounts:
- type: template
source: config.yaml.j2
destination: /data/config.yaml
service_container_secrets:
- name: as-token
value: "{{ mautrix_whatsapp_as_token }}"
- name: hs-token
value: "{{ mautrix_whatsapp_hs_token }}"
- name: doublepuppet-token
value: as_token:{{ mautrix_whatsapp_doublepuppet_token }}
- name: encryption-pickle-key
service_container_env:
BRIDGE_DATABASE__URI_FILE: /run/secrets/postgres-url
BRIDGE_APPSERVICE__AS_TOKEN_FILE: /run/secrets/as-token
BRIDGE_APPSERVICE__HS_TOKEN_FILE: /run/secrets/hs-token
BRIDGE_ENCRYPTION__PICKLE_KEY: /run/secrets/encryption-pickle-key
"BRIDGE_DOUBLE_PUPPET__SECRETS__{{ mautrix_whatsapp_homeserver_name }}": /run/secrets/doublepuppet-token

View File

@@ -0,0 +1,73 @@
---
# vim:ft=yaml
# {{ ansible_managed }}
network:
os_name: "{{ mautrix_whatsapp_os_name }}"
send_presence_on_typing: true
url_previews: true
extev_polls: true
bridge:
cleanup_on_logout:
enabled: true
manual:
private: nothing
relayed: nothing
shared_no_users: kick
shared_has_users: kick
bad_credentials:
private: nothing
relayed: nothing
shared_no_users: kick
shared_has_users: kick
relay:
enabled: true
admin_only: true
default_relays:
{{ mautrix_whatsapp_default_relays | to_nice_yaml | indent(4) }}
permissions:
"*": relay
{% for item in mautrix_whatsapp_permissions %}
"{{ item.key }}": {{ item.value }}
{% endfor %}
database:
type: postgres
homeserver:
address: http://synapse:8009
domain: {{ mautrix_whatsapp_homeserver_name }}
async_media: true
appservice:
address: http://mautrix-whatsapp:8080
hostname: 0.0.0.0
port: 8080
id: whatsapp
bot:
username: whatsappbot
displayname: {{ mautrix_whatsapp_bot_displayname }}
matrix:
delivery_receipts: true
provisioning:
shared_secret: disable
encryption:
allow: true
default: false
msc4190: true
allow_key_sharing: true
env_config_prefix: BRIDGE_
logging:
min_level: info
writers:
- type: stdout
format: pretty-colored

View File

@@ -0,0 +1,2 @@
---
_mautrix_whatsapp_image: dock.mau.dev/mautrix/whatsapp:latest

View File

@@ -1,3 +1,4 @@
---
nextcloud_tag: stable
nextcloud_install_harp: false
nextcloud_additional_networks: []

View File

@@ -2,6 +2,7 @@
- name: Unregister AppAPI daemon
containers.podman.podman_container_exec:
name: nextcloud
user: www-data
argv:
- /var/www/html/occ
- app_api:daemon:unregister
@@ -14,6 +15,7 @@
- name: Register AppAPI daemon
containers.podman.podman_container_exec:
name: nextcloud
user: www-data
argv:
- /bin/sh
- -c

View File

@@ -22,3 +22,9 @@ argument_specs:
type: bool
required: false
default: false
nextcloud_additional_networks:
description: Additional docker networks to add nextcloud container to
type: list
elements: str
required: false
default: []

View File

@@ -29,3 +29,4 @@
NEXTCLOUD_ADMIN_PASSWORD_FILE: /run/secrets/admin-password
service_additional_containers: "{{ _nextcloud_additional_containers }}"
service_vhost_locations: "{{ _nextcloud_vhost_locations }}"
service_container_additional_networks: "{{ nextcloud_additional_networks }}"

View File

@@ -9,6 +9,7 @@ service_proxy_pass_host_header: true
service_proxy_auth_type: none
service_container_ip: ""
service_container_hostname: ""
service_container_additional_networks: []
service_container_user: ""
service_container_publish_ports: []
@@ -17,6 +18,8 @@ service_container_devices: []
service_container_secrets: []
service_container_env: {}
service_container_add_capabilities: []
service_container_reload_method: none
service_container_reload_command: ""
service_database_type: none
service_database_additional_networks: []
@@ -25,6 +28,9 @@ service_database_secret_target: "{{ service_database_type }}"
service_postgres_image: docker.io/pgautoupgrade/pgautoupgrade
service_postgres_tag: alpine
service_redis: false
service_tailscale: false
service_tailscale_login_server: ""
service_tailscale_apikey: ""
service_additional_containers: []

View File

@@ -29,7 +29,7 @@ argument_specs:
service_container_http_port:
description:
- Port inside the container where http requests are proxied to.
- If set to 0, http requests are proxied to /run/<service name>.sock inside the container
- If set to 0, http requests are proxied to fd:3 inside the container
type: int
required: false
default: 0
@@ -82,6 +82,11 @@ argument_specs:
type: str
required: false
default: ""
service_container_hostname:
description: Hostname to set inside the container.
type: str
required: false
default: ""
service_container_additional_networks:
description: >-
A list of additional podman networks for the service container (in
@@ -108,6 +113,14 @@ argument_specs:
description: Container port to publish
type: int
required: true
protocol:
description: Protocol of the port
type: str
required: false
default: tcp
choices:
- tcp
- udp
type:
description: Whether to publish as a port or socket
type: str
@@ -150,7 +163,7 @@ argument_specs:
- 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
- If mount type is template, the name of the template file, must end in .j2.
- If mount type is copy, name of the file or directory to copy. Directory name must end in /.
type: str
required: true
@@ -202,6 +215,23 @@ argument_specs:
elements: str
required: false
default: []
template_validate_command:
description: >-
Command used to verify templated file validity.
Will be run in a temporary container using the same container image as the main service.
File will be available in the same place as in the service container (destination).
Only applicable if mount type is template.
type: str
required: false
template_directory:
description: >-
Whether to create a directory and mount it at the destination file's parent directory.
This is required for container to see templated file changes without restart.
Only applicable if mount type is template.
type: bool
required: false
default: false
service_container_devices:
description: List of devices to be added inside the service main container.
type: list
@@ -277,6 +307,26 @@ argument_specs:
default: []
elements: str
service_container_reload_method:
description: |
How to reload configuration when systemctl reload is called
kill: Sends SIGHUP to the container
command: Runs the specified command inside the container
type: str
required: false
default: none
choices:
- kill
- command
- none
service_container_reload_command:
description: >-
Command to run inside container when systemctl reload is called.
Required if container_reload_method is command, ignored otherwise.
type: str
required: false
default: ""
service_database_type:
description:
- Database type to set up.
@@ -285,6 +335,7 @@ argument_specs:
host <service database type> on the default port.
- The database user will be <service name>
- The password will be accessible as secret at /run/secrets/<service database type>
- A postgres url is accessible as secret at /run/secrets/postgres-url
- >
The password will also be available as the
service_podman_secrets['<service name>-<service database type>'] variable.
@@ -336,6 +387,23 @@ argument_specs:
type: bool
required: false
default: false
service_tailscale:
description: >-
Whether to install tailscale in a container and have the service container use its
network. This will make the container accessible over tailscale.
type: bool
required: false
default: false
service_tailscale_login_server:
description: Tailscale login server. Required if tailscale is enabled.
type: str
required: false
default: ""
service_tailscale_apikey:
description: Tailscale API key. Required if tailscale is enabled.
type: str
required: false
default: ""
service_additional_containers:
description:
@@ -482,7 +550,7 @@ argument_specs:
- Name of the port.
- >-
If type is socket, the socket will be created at
/run/<service name>-<additional container name>-<port name>.sock on the host.
/run/<service name>-<port name>-socat.sock on the host.
- If type is not socket, this is just informative.
type: str
required: true
@@ -490,6 +558,14 @@ argument_specs:
description: Container port to publish
type: int
required: true
protocol:
description: Protocol of the port
type: str
required: false
default: tcp
choices:
- tcp
- udp
type:
description: Whether to publish as a port or socket
type: str
@@ -524,6 +600,32 @@ argument_specs:
type: list
required: false
elements: str
reload_method:
description: |
How to reload configuration when systemctl reload is called
kill: Sends SIGHUP to the container
command: Runs the specified command inside the container
type: str
required: false
default: none
choices:
- kill
- command
- none
reload_command:
description: >-
Command to run inside container when systemctl reload is called.
Required if container_reload_method is command, ignored otherwise.
type: str
required: false
default: ""
tailscale:
description: >-
Whether to install tailscale in a container and this container use its
network. This will make the container accessible over tailscale.
type: bool
required: false
default: false
secrets:
description:
- >
@@ -571,6 +673,23 @@ argument_specs:
the name of the environment variable. Defaults to secret name.
type: str
required: false
requires:
description: >-
List of systemd units this container depends on, in addition to
service-wide requires.
type: list
required: false
default: []
elements: str
wants:
description: >-
List of systemd units this container weakly depends on, in addition to
service-wide wants.
type: list
required: false
default: []
elements: str
service_requires:
description: List of systemd units this service container depends on.

View File

@@ -1,5 +1,5 @@
---
- name: Additional containers for {{ service_name }}
- name: Additional container {{ _service_additional_container.name }}
ansible.builtin.include_role:
name: container
vars:
@@ -11,21 +11,37 @@
container_mounts: "{{ _service_additional_container_mounts }}"
container_devices: "{{ _service_additional_container.devices }}"
container_publish_ports: "{{ _service_additional_container_publish_ports }}"
container_networks: "{{ _service_additional_container_networks }}"
container_networks: >-
{{
_service_additional_container_networks if not _service_additional_container.tailscale
else [{'name': _service_additional_container.name ~ '-tailscale.container'}]
}}
container_hostname: "{{ _service_additional_container.name | regex_replace('^' ~ service_name ~ '-', '') }}"
container_secrets: "{{ _service_additional_container_secrets }}"
container_env: "{{ _service_additional_container.env }}"
container_add_capabilities: "{{ _service_additional_container.add_capabilities }}"
container_requires: "{{ _service_container_requires }}"
container_reload_method: "{{ _service_additional_container.reload_method }}"
container_reload_command: "{{ _service_additional_container.reload_command }}"
container_requires: "{{ _service_additional_container_requires }}"
container_wants: "{{ _service_additional_container_wants }}"
container_auto_update: "{{ service_auto_update }}"
loop: "{{ _service_additional_containers }}"
loop_control:
loop_var: _service_additional_container
index_var: _service_additional_container_index
- name: Socat sockets for additional containers of {{ service_name }}
ansible.builtin.include_tasks: additional_socat.yaml
loop: "{{ _service_additional_containers }}"
- name: Socat for socket published ports of {{ _service_additional_container.name }}
ansible.builtin.include_role:
name: socat
loop: "{{ _service_additional_container_publish_socket_ports }}"
loop_control:
loop_var: _service_additional_container
loop_var: publish_port
vars:
socat_service_name: "{{ service_name }}-{{ publish_port.name }}"
socat_target_container: "{{ _service_additional_container.name }}"
socat_target_http_port: "{{ publish_port.container_port }}"
socat_auto_update: "{{ service_auto_update }}"
- name: Tailscale for {{ _service_additional_container.name }}
ansible.builtin.include_tasks: tailscale.yaml
when: _service_additional_container.tailscale
vars:
_service_tailscale_container_name: "{{ _service_additional_container.name }}"
_service_tailscale_networks: "{{ _service_additional_container_networks }}"
_service_tailscale_hostname: "{{ _service_additional_container.name | regex_replace('^' ~ service_name ~ '-', '') }}"

View File

@@ -1,12 +0,0 @@
---
- name: Socat for socket published ports of {{ service_name }}
ansible.builtin.include_role:
name: socat
loop: "{{ _service_additional_container_publish_socket_ports }}"
loop_control:
loop_var: publish_port
vars:
socat_service_name: "{{ service_name }}-{{ publish_port.name }}"
socat_target_container: "{{ _service_additional_container.name }}"
socat_target_http_port: "{{ publish_port.container_port }}"
socat_auto_update: "{{ service_auto_update }}"

View File

@@ -13,18 +13,29 @@
- name: Create service template mount directories
ansible.builtin.file:
path: "{{ _service_host_directory }}/mounts/{{ item }}"
path: "{{ item }}"
state: directory
mode: "0700"
loop: "{{ _service_all_template_mount_directories }}"
loop: "{{ _service_all_template_mount_host_files | map('dirname') | unique }}"
- name: Template files for template mounts
ansible.builtin.template:
src: "{{ item[0].source }}"
dest: "{{ item[1] }}"
mode: "{{ item[0].mode | default('0644') }}"
notify: Restart container service {{ service_name }}
loop: "{{ _service_all_template_mounts | zip(_service_all_template_mount_host_files) }}"
src: "{{ item.source }}"
dest: "{{ item.hostfile }}"
mode: "{{ item.mode | default('0644') }}"
validate: "{{ validate if item.template_validate_command is defined else omit }}"
notify: >-
{{ 'Reload' if service_container_reload_method != 'none' else 'Restart' }}
container service {{ service_name }}
loop: "{{ _service_all_template_mounts_full }}"
vars:
validate: "{{ _service_template_validate_command }}"
- name: Ensure no legacy templated files present
ansible.builtin.file:
path: "{{ _service_host_directory }}/mounts/{{ item.source | regex_replace('\\.j2$', '') }}"
state: absent
loop: "{{ _service_all_template_mounts_full }}"
- name: Copy files for copy mounts
ansible.builtin.copy:

View File

@@ -5,14 +5,21 @@
- name: Database for {{ service_name }}
ansible.builtin.include_tasks: database.yaml
when: _service_setup_database
- name: Redis for {{ service_name }}
ansible.builtin.include_tasks: redis.yaml
when: service_redis
- name: Secrets for {{ service_name }}
ansible.builtin.include_tasks: secrets.yaml
when: _service_container_secrets | length > 0
when: _service_container_secrets | length > 0 or service_tailscale
- name: Tailscale for {{ service_name }}
ansible.builtin.include_tasks: tailscale.yaml
when: service_tailscale
vars:
_service_tailscale_container_name: "{{ service_name }}"
_service_tailscale_networks: "{{ _service_networks }}"
_service_tailscale_hostname: "{{ service_name }}"
- name: Template mounts for {{ service_name }}
ansible.builtin.include_tasks: host_mounts.yaml
@@ -20,7 +27,10 @@
- name: Additional containers for {{ service_name }}
ansible.builtin.include_tasks: additional.yaml
when: _service_additional_containers | length > 0
loop: "{{ _service_additional_containers }}"
loop_control:
loop_var: _service_additional_container
index_var: _service_additional_container_index
- name: Native socket for {{ service_name }}
ansible.builtin.include_role:
@@ -44,9 +54,12 @@
container_devices: "{{ service_container_devices }}"
container_publish_ports: "{{ _service_container_publish_ports }}"
container_networks: "{{ _service_container_networks }}"
container_hostname: "{{ service_container_hostname }}"
container_secrets: "{{ _service_container_secrets }}"
container_env: "{{ service_container_env }}"
container_add_capabilities: "{{ service_container_add_capabilities }}"
container_reload_method: "{{ service_container_reload_method }}"
container_reload_command: "{{ service_container_reload_command }}"
container_requires: "{{ _service_container_requires }}"
container_wants: "{{ _service_container_wants }}"
container_auto_update: "{{ service_auto_update }}"

View File

@@ -8,5 +8,9 @@
container_networks:
- name: "{{ service_name }}"
ip: "{{ service_container_ip | ansible.utils.ipmath(2) if _service_static_ip else '' }}"
container_mounts:
- type: volume
source: "{{ service_name }}-redis"
destination: /data
container_hostname: redis
container_auto_update: "{{ service_auto_update }}"

View File

@@ -0,0 +1,60 @@
---
- name: Create tailscale preauthkey secret for {{ _service_tailscale_container_name }}
when:
- not ansible_check_mode
- "_service_tailscale_container_name ~ '-tailscale-preauthkey' not in service_podman_secrets"
block:
- name: Get preauthkey from tailscale API
ansible.builtin.uri:
url: "{{ service_tailscale_login_server }}/api/v1/preauthkey"
headers:
Authorization: Bearer {{ service_tailscale_apikey }}
method: POST
body:
expiration: >-
{{
now(utc=true).replace(
day=now(utc=true).day if now(utc=true).hour != 23 else now(utc=true).day + 1,
hour=now(utc=true).hour + 1 if now(utc=true).hour != 23 else 0
).isoformat()
}}Z
aclTags:
- tag:container
- "tag:{{ _service_tailscale_container_name }}"
body_format: json
register: _service_tailscale_preauthkey
- name: Create preauthkey secret
containers.podman.podman_secret:
name: "{{ _service_tailscale_container_name }}-tailscale-preauthkey"
data: "{{ _service_tailscale_preauthkey.json.preAuthKey.key }}"
no_log: true
- name: Tailscale container for {{ _service_tailscale_container_name }}
ansible.builtin.import_role:
name: container
vars:
container_name: "{{ _service_tailscale_container_name }}-tailscale"
container_image: docker.io/tailscale/tailscale:latest
container_networks: "{{ _service_tailscale_networks }}"
container_hostname: "{{ _service_tailscale_hostname }}"
container_add_capabilities:
- NET_ADMIN
container_devices:
- source: /dev/net/tun
container_mounts:
- type: volume
source: "{{ _service_tailscale_container_name }}-tailscale"
destination: /var/lib/tailscale
container_auto_update: "{{ service_auto_update }}"
container_secrets:
- name: "{{ _service_tailscale_container_name }}-tailscale-preauthkey"
target: preauthkey
container_env:
TS_STATE_DIR: /var/lib/tailscale
TS_AUTHKEY: file:/run/secrets/preauthkey
TS_EXTRA_ARGS: --login-server={{ service_tailscale_login_server }}
TS_HOSTNAME: "{{ _service_tailscale_container_name }}"
TS_AUTH_ONCE: "true"
TS_NO_LOGS_NO_SUPPORT: "true"
TS_USERSPACE: "false"
TS_ACCEPT_DNS: "true"

View File

@@ -1,7 +1,13 @@
---
_service_additional_container_defaults:
image: "{{ service_container_image }}"
tailscale: false
requires: []
wants: []
_service_additional_containers_with_default_image: >-
{{
([{ 'image': service_container_image }] * service_additional_containers | length)
([_service_additional_container_defaults] * service_additional_containers | length)
| zip(service_additional_containers)
| map('combine')
}}
@@ -13,6 +19,8 @@ _service_additional_container_same_image_defaults:
devices: "{{ service_container_devices }}"
env: "{{ service_container_env }}"
add_capabilities: "{{ service_container_add_capabilities }}"
reload_method: "{{ service_container_reload_method }}"
reload_command: "{{ service_container_reload_command }}"
_service_additional_container_different_image_defaults:
user: ""
@@ -23,6 +31,8 @@ _service_additional_container_different_image_defaults:
publish_ports: []
env: {}
add_capabilities: []
reload_method: none
reload_command: ""
secrets: []
_service_additional_same_image_containers: >-
@@ -72,13 +82,16 @@ _service_additional_containers: >-
_service_additional_container_wants: >-
{{
service_wants
+ _service_additional_container_publish_socket_ports
service_wants + _service_additional_container.wants +
_service_additional_container_publish_socket_ports
| map(attribute='name')
| map('regex_replace', '^', service_name ~ '-')
| map('regex_replace', '$', '-socat.socket')
}}
_service_additional_container_requires: >-
{{ _service_container_requires + _service_additional_container.requires }}
_service_additional_container_networks: >-
{{
[{
@@ -144,6 +157,7 @@ _service_additional_container_publish_ports: >-
_service_additional_container_publish_port_ports | map(attribute='host_port'),
_service_additional_container_publish_port_ports | map(attribute='container_port')
) | map('join', ':')
| zip(_service_additional_container_publish_port_ports | map(attribute='protocol')) | map('join', '/')
}}
_service_additional_volume_mounts: "{{ _service_additional_container.mounts | selectattr('type', '==', 'volume') }}"
@@ -168,7 +182,7 @@ _service_additional_container_template_mounts: >-
([{'readonly': true}] * _service_additional_template_mounts | length) |
zip(
_service_additional_template_mounts |
community.general.remove_keys(['mode']),
community.general.remove_keys(['mode', 'template_validate_command']),
_service_additional_template_mounts |
map(attribute='source') |
map('regex_replace', '\.j2$', '') |

View File

@@ -1,5 +1,5 @@
---
_service_container_networks: >-
_service_networks: >-
{{
[{
'name': service_name,
@@ -21,6 +21,10 @@ _service_container_networks: >-
)
) | map('community.general.dict_kv', 'name')
}}
_service_container_networks: >-
{{
[{'name': service_name ~ '-tailscale.container'}] if service_tailscale else _service_networks
}}
_service_static_ip: "{{ service_container_ip | length > 0 }}"
_service_container_requires: >-

View File

@@ -25,21 +25,60 @@ _service_container_bind_mounts: >-
service_container_mounts | selectattr('type', '==', 'bind') +
([ _service_container_socket_mount ] if _service_native_socket else [])
}}
_service_container_template_mounts: >-
_service_template_mounts_hostfiles: >-
{{
([{'readonly': true}] * _service_template_mounts | length) |
zip(
_service_template_mounts |
community.general.remove_keys(['mode']),
_service_template_mounts |
map(attribute='source') |
map('regex_replace', '\.j2$', '') |
map('regex_replace', '^', _service_host_directory ~ '/mounts/') |
map('community.general.dict_kv', 'source'),
([{'type': 'bind'}] * _service_template_mounts | length)
_service_template_mounts
| map(attribute='destination')
| map('dirname')
| map('replace', '/', '_')
| map('regex_replace', '^', _service_host_directory ~ '/mounts/')
| zip(
_service_template_mounts
| map(attribute='destination')
| map('basename')
)
| map('path_join')
| map('community.general.dict_kv', 'hostfile')
}}
_service_template_mounts_full: >-
{{
([{'readonly': true, 'template_directory': false}] * _service_template_mounts | length)
| zip(
_service_template_mounts,
_service_template_mounts_hostfiles
)
| map('combine')
}}
_service_template_mounts_plain: "{{ _service_template_mounts_full | rejectattr('template_directory') }}"
_service_container_template_mounts_plain: >-
{{
_service_template_mounts_plain
| community.general.remove_keys(['mode', 'template_validate_command', 'template_directory', 'hostfile'])
| zip(
_service_template_mounts_plain
| map(attribute='hostfile')
| map('community.general.dict_kv', 'source'),
([{'type': 'bind'}] * _service_template_mounts_plain | length)
) |
map('combine')
}}
_service_template_mounts_directory: "{{ _service_template_mounts_full | selectattr('template_directory') }}"
_service_container_template_mounts_directory: >-
{{
_service_template_mounts_directory
| community.general.remove_keys(['mode', 'template_validate_command', 'template_directory', 'hostfile'])
| zip(
_service_template_mounts_directory
| map(attribute='hostfile')
| map('dirname')
| map('community.general.dict_kv', 'source'),
([{'type': 'bind'}] * _service_template_mounts_directory | length)
)
| map('combine')
| unique
}}
_service_container_copy_mounts: >-
{{
([{'readonly': true}] * _service_copy_mounts | length) |
@@ -58,40 +97,49 @@ _service_container_copy_mounts: >-
_service_container_mounts: >-
{{
_service_container_volume_mounts +
_service_container_bind_mounts +
_service_container_template_mounts +
_service_container_copy_mounts
_service_container_volume_mounts
+ _service_container_bind_mounts
+ _service_container_template_mounts_plain
+ _service_container_template_mounts_directory
+ _service_container_copy_mounts
}}
_service_all_template_mounts: >-
{{
(
_service_template_mounts +
(
_service_additional_containers |
map(attribute='mounts', default=[]) |
flatten
_service_template_mounts
+ (
_service_additional_containers
| map(attribute='mounts', default=[])
| flatten
)
) |
selectattr('type', '==', 'template') |
unique
}}
_service_all_template_mount_directories: >-
{{
_service_all_template_mounts |
map(attribute='source') |
map('dirname') |
unique |
select('!=', '')
)
| selectattr('type', '==', 'template')
| unique
}}
_service_all_template_mount_host_files: >-
{{
_service_all_template_mounts |
map(attribute='source') |
map('regex_replace', '\.j2$', '') |
map('regex_replace', '^', _service_host_directory ~ '/mounts/')
_service_all_template_mounts
| map(attribute='destination')
| map('dirname')
| map('replace', '/', '_')
| map('regex_replace', '^', _service_host_directory ~ '/mounts/')
| zip(
_service_all_template_mounts
| map(attribute='destination')
| map('basename')
)
| map('path_join')
}}
_service_all_template_mounts_full: >-
{{
([{'readonly': true, 'template_directory': false}] * _service_all_template_mounts | length)
| zip(
_service_all_template_mounts,
_service_all_template_mount_host_files | map('community.general.dict_kv', 'hostfile')
)
| map('combine')
}}
_service_all_copy_mounts: >-
@@ -109,7 +157,7 @@ _service_all_copy_mounts: >-
}}
_service_all_copy_mount_host_files: >-
{{
_service_all_copy_mounts |
map(attribute='source') |
map('regex_replace', '^', _service_host_directory ~ '/mounts/')
_service_all_copy_mounts
| map(attribute='source')
| map('regex_replace', '^', _service_host_directory ~ '/mounts/')
}}

View File

@@ -1,7 +1,7 @@
---
_service_container_publish_ports_with_defaults: >-
{{
([{ 'type': 'port', 'host_address': '0.0.0.0' }] * service_container_publish_ports | length)
([{ 'type': 'port', 'host_address': '0.0.0.0', 'protocol': 'tcp' }] * service_container_publish_ports | length)
| zip(service_container_publish_ports)
| map('combine')
}}
@@ -13,9 +13,10 @@ _service_container_publish_port_ports: >-
_service_container_publish_ports: >-
{{
_service_container_publish_port_ports | map(attribute='host_address') |
zip(
_service_container_publish_port_ports | map(attribute='host_address')
| zip(
_service_container_publish_port_ports | map(attribute='host_port'),
_service_container_publish_port_ports | map(attribute='container_port')
) | map('join', ':')
| zip(_service_container_publish_port_ports | map(attribute='protocol')) | map('join', '/')
}}

View File

@@ -2,34 +2,34 @@
_service_container_secrets: >-
{{
service_container_secrets
| map(attribute='name')
| map('community.general.dict_kv', 'target')
| zip(
service_container_secrets,
service_container_secrets
| map(attribute='name')
| map('community.general.dict_kv', 'target')
| zip(
service_container_secrets,
service_container_secrets
| map(attribute='name')
| map('regex_replace', '^', service_name ~ '-')
| map('community.general.dict_kv', 'name')
)
| map('combine')
+ (
[{
'name': _service_database_name,
'type': service_database_secret_type,
'target': service_database_secret_target
}] if _service_setup_database else []
)
+ (
[{
'name': _service_database_name ~ '-url',
'value':
'postgres://'
~ service_name | replace('-', '_')
~ ':' ~ service_podman_secrets[service_name ~ '-postgres']
~ '@postgres/' ~ service_name | replace('-', '_')
~ '?sslmode=disable',
'type': service_database_secret_type,
'target': service_database_secret_target ~ '-url'
}] if service_podman_secrets[service_name ~ '-postgres'] is defined else []
)
| map('regex_replace', '^', service_name ~ '-')
| map('community.general.dict_kv', 'name')
)
| map('combine')
+ (
[{
'name': _service_database_name,
'type': service_database_secret_type,
'target': service_database_secret_target
}] if _service_setup_database else []
)
+ (
[{
'name': _service_database_name ~ '-url',
'value':
'postgres://'
~ service_name | replace('-', '_')
~ ':' ~ service_podman_secrets[service_name ~ '-postgres']
~ '@postgres/' ~ service_name | replace('-', '_')
~ '?sslmode=disable',
'type': service_database_secret_type,
'target': service_database_secret_target ~ '-url'
}] if service_podman_secrets[service_name ~ '-postgres'] is defined else []
)
}}

View File

@@ -0,0 +1,24 @@
---
_service_template_validate_secrets: >-
{{
_service_container_secrets
| map(attribute='name')
| zip(
_service_container_secrets
| community.general.remove_keys(['name', 'value', 'length'])
| map('items')
| map('map', 'join', '=')
| map('join', ',')
)
| map('join', ',')
| map('regex_replace', '^', '--secret ')
| join(' ')
}}
_service_template_validate_command: >-
podman run --rm
-v %s:{{ item.destination }}:ro
--entrypoint {{ item.template_validate_command.split(' ', 1)[0] }}
{{ _service_template_validate_secrets }}
{{ service_container_image }}
{{ item.template_validate_command.split(' ', 1)[1] }}

View File

@@ -19,3 +19,5 @@ synapse_auto_join_rooms: []
synapse_smtp_server: ""
synapse_oidc_provider_client_id: ""
synapse_appservices: []

View File

@@ -116,3 +116,29 @@ argument_specs:
type: str
required: false
default: 16-alpine
synapse_appservices:
description: List of appservices to run with synapse. They will be installed in separate containers.
type: list
required: false
default: []
elements: dict
options:
id:
description: A unique, user-defined ID of the application service which will never change
type: str
required: true
host:
description: Hostname the appservice is accessible to synapse at
type: str
required: true
as_token:
description: A secret token that the application service will use to authenticate requests to the homeserver
type: str
required: true
hs_token:
description: A secret token that the homeserver will use authenticate requests to the application service
type: str
required: true
synapse_doublepuppet_token:
description: Double puppeting token for appservices. Required if synapse_appservices is not empty.

View File

@@ -15,26 +15,11 @@
name: service
vars:
service_name: synapse
service_container_image: "{{ _synapse_image_name }}"
service_container_image: ghcr.io/element-hq/synapse:latest
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 }}"
- name: mas-client-secret
- name: mas-homeserver-secret
service_container_mounts: "{{ _synapse_mounts }}"
service_container_secrets: "{{ _synapse_secrets }}"
service_container_env:
SYNAPSE_SERVER_NAME: "{{ synapse_server_name }}"
SYNAPSE_REPORT_STATS: "no"
@@ -44,16 +29,17 @@
service_domains: "{{ [synapse_external_domain] }}"
service_vhost_locations:
- path: ^/_matrix/client/.*/(login|logout|refresh).*$
proxy_target_socket: /run/matrix-authentication-service-socat.sock
proxy_target_socket: /run/matrix-authentication-service-caddy-socket-proxy.sock
service_wants:
- matrix-authentication-service.service
service_container_additional_networks: "{{ _synapse_additional_networks }}"
- name: Matrix authentication service for synapse
ansible.builtin.import_role:
name: matrix_authentication_service
vars:
matrix_authentication_service_additional_networks:
- synapse
- synapse-mas
matrix_authentication_service_secrets: "{{ synapse_mas_secrets }}"
matrix_authentication_service_domain: "{{ synapse_mas_domain }}"
matrix_authentication_service_homeserver_name: "{{ synapse_server_name }}"

View File

@@ -0,0 +1,21 @@
---
# vim:ft=yaml
# {{ ansible_managed }}
{% set id = item.destination.split('/')[-1].split('-')[0] %}
{% set appservice = synapse_appservices | selectattr('id', 'equalto', id) | first %}
id: {{ id }}
url: http://{{ appservice.host }}:8080
as_token: {{ appservice.as_token }}
hs_token: {{ appservice.hs_token }}
sender_localpart: {{ id }}senderlocalpart
rate_limited: false
namespaces:
users:
- regex: ^@{{ id }}bot:{{ synapse_server_name | replace('.', '\.') }}$
exclusive: true
- regex: ^@{{ id }}_.*:{{ synapse_server_name | replace('.', '\.') }}$
exclusive: true
de.sorunome.msc2409.push_ephemeral: true
receive_ephemeral: true
io.element.msc4190: true

View File

@@ -0,0 +1,15 @@
---
# vim:ft=yaml
# {{ ansible_managed }}
id: doublepuppet
url:
as_token: "{{ synapse_doublepuppet_token }}"
hs_token: doublepuppethstoken
sender_localpart: doublepuppetsenderlocalpart
rate_limited: false
namespaces:
users:
- regex: '@.*:{{ synapse_server_name | replace(".", "\.") }}'
exclusive: false

View File

@@ -81,7 +81,7 @@ url_preview_ip_range_blacklist:
turn_uris: {{ synapse_turn_uris }}
{% if synapse_turn_uris | length > 0 %}
turn_shared_secret: {{ synapse_turn_shared_secret }}
turn_shared_secret_file: /run/secrets/turn-shared-secret
{% endif %}
turn_user_lifetime: 1d
turn_allow_guests: false
@@ -106,12 +106,13 @@ auto_accept_invites: {{ synapse_auto_accept_invites }}
auto_join_rooms: {{ synapse_auto_join_rooms }}
autocreate_auto_join_rooms: false
experimental_features:
msc3861:
enabled: true
issuer: http://matrix-authentication-service:8080/
client_id: 0000000000000000000SYNAPSE
client_auth_method: client_secret_basic
client_secret: "{{ service_podman_secrets['synapse-mas-client-secret'] }}"
admin_token: "{{ service_podman_secrets['synapse-mas-homeserver-secret'] }}"
account_management_url: "https://{{ synapse_mas_domain }}/account"
matrix_authentication_service:
enabled: true
endpoint: http://matrix-authentication-service:8080/
secret_path: /run/secrets/mas-homeserver-secret
{% if synapse_appservices | length > 0 %}
app_service_config_files:
- {{ _synapse_doublepuppet_registration_mount.destination }}
{{ _synapse_appservice_registration_mounts | map(attribute='destination') | to_nice_yaml | indent(2) }}
{% endif %}

View File

@@ -1,2 +1,59 @@
---
_synapse_image_name: ghcr.io/element-hq/synapse:latest
_synapse_additional_networks: >-
{{
['synapse-mas']
+ (
synapse_appservices
| map(attribute='host')
| map('regex_replace', '^', 'synapse-')
)
}}
_synapse_main_secrets:
- name: signing-key
value: "{{ synapse_signing_key }}"
- name: mas-client-secret
- name: mas-homeserver-secret
_synapse_turn_secrets:
- name: turn-shared-secret
value: "{{ synapse_turn_shared_secret }}"
_synapse_secrets: >-
{{
_synapse_main_secrets
+ (_synapse_turn_secrets if synapse_turn_uris | length > 0 else [])
}}
_synapse_base_mounts:
- type: template
source: homeserver.yaml.j2
destination: /data/homeserver.yaml
template_validate_command: python -m synapse.config -c /data/homeserver.yaml --no-secrets-in-config
- type: template
source: log.yaml.j2
destination: /data/log.yaml
- type: volume
source: media
destination: /data/media
user: "991"
group: "991"
_synapse_doublepuppet_registration_mount:
type: template
source: doublepuppet-registration.yaml.j2
destination: /data/doublepuppet-registration.yaml
_synapse_appservice_registration_mounts: >-
{{
([{'type': 'template', 'source': 'appservice-registration.yaml.j2'}] * synapse_appservices | length)
| zip(
synapse_appservices
| map(attribute='id')
| map('regex_replace', '^', '/data/appservices/')
| map('regex_replace', '$', '-registration.yaml')
| map('community.general.dict_kv', 'destination')
) | map('combine')
}}
_synapse_mounts: >-
{{
_synapse_base_mounts
+ ([_synapse_doublepuppet_registration_mount] if synapse_appservices | length > 0 else [])
+ _synapse_appservice_registration_mounts
}}

1
roles/windmill/README.md Normal file
View File

@@ -0,0 +1 @@
Installs windmill with worker in podman in podman

View File

@@ -17,34 +17,56 @@
DATABASE_URL_FILE: /run/secrets/postgres-url
MODE: server
service_additional_containers:
- name: worker
- name: worker-pinp
image: quay.io/podman/stable:latest
user: podman
entrypoint: /entrypoint.sh
command:
- podman
- system
- service
- --time
- "0"
mounts:
- type: volume
source: worker-pinp-containers
destination: /home/podman/.local/share/containers
- type: volume
source: worker-pinp-tmp
destination: /tmp/storage-run-1000
- type: volume
source: worker-pinp-run
destination: /tmp/storage-run-1000/podman
- name: worker
mounts:
- type: volume
source: worker-logs
destination: /worker-logs
destination: /tmp/windmill/logs
- type: volume
source: worker-dependency-cache
destination: /worker-dependency-cache
- type: template
source: worker_entrypoint.sh.j2
destination: /entrypoint.sh
mode: "0755"
destination: /tmp/windmill/cache
- type: volume
source: worker-containers
destination: /home/podman/.local/share/containers
publish_ports: []
env: {}
source: worker-pinp-run
destination: /run/podman
readonly: true
env:
DATABASE_URL_FILE: /run/secrets/postgres-url
DOCKER_HOST: unix:///run/podman/podman.sock
MODE: worker
WORKER_GROUP: default
ENABLE_UNSHARE_PID: "true"
UNSHARE_ISOLATION_FLAGS: "--user --map-root-user --pid --fork"
wants:
- windmill-worker-pinp.service
- name: worker-native
env:
DATABASE_URL_FILE: /run/secrets/postgres-url
MODE: worker
WORKER_TYPE: native
WORKER_GROUP: native
NATIVE_MODE: "true"
NUM_WORKERS: "8"
SLEEP_QUEUE: "200"
ENABLE_UNSHARE_PID: "true"
UNSHARE_ISOLATION_FLAGS: "--user --map-root-user --pid --fork"
- name: lsp
image: ghcr.io/windmill-labs/windmill-extra:latest
secrets: []

View File

@@ -1,27 +0,0 @@
#!/bin/bash
# {{ ansible_managed }}
_term() {
echo "Received SIGTERM, stopping all containers"
kill "$child"
}
podman system service -t 0 &
podman run \
--rm \
-v /run/secrets/postgres-url:/run/secrets/postgres-url:ro \
-e DATABASE_URL_FILE=/run/secrets/postgres-url \
-e MODE=worker \
-e WORKER_GROUP=default \
-e ENABLE_UNSHARE_PID="true" \
-e UNSHARE_ISOLATION_FLAGS="--user --map-root-user --pid --fork" \
-v /tmp/storage-run-1000/podman/podman.sock:/var/run/docker.sock \
-v /worker-logs:/tmp/windmill/logs \
-v /worker-dependency-cache:/tmp/windmill/cache \
--name worker \
--network host \
ghcr.io/windmill-labs/windmill:main &
child=$!
trap _term SIGTERM
wait "$!"