feat(ess-pro/compose): deploy Element Server Suite Pro via Compose
initial commit of the converted role from helm charts for qubernetis to compose ansible role
This commit is contained in:
parent
c11f019aae
commit
32eca6b923
33 changed files with 1906 additions and 0 deletions
79
roles/ess_pro_compose/tasks/config.yml
Normal file
79
roles/ess_pro_compose/tasks/config.yml
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
# SPDX-License-Identifier: MIT-0
|
||||
---
|
||||
# Render every component's configuration. Each template uses _ess_secrets
|
||||
# facts (loaded in secrets.yml) for password substitution.
|
||||
|
||||
- name: Render HAProxy config
|
||||
ansible.builtin.template:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ ess_compose_conf_dir }}/haproxy/{{ item.dest }}"
|
||||
mode: "0640"
|
||||
loop:
|
||||
- { src: haproxy/haproxy.cfg.j2, dest: haproxy.cfg }
|
||||
- { src: haproxy/429.http.j2, dest: 429.http }
|
||||
- { src: haproxy/path_map_file.j2, dest: path_map_file }
|
||||
- { src: haproxy/path_map_file_get.j2, dest: path_map_file_get }
|
||||
- { src: haproxy/admin-allow-ips.lst.j2, dest: admin-allow-ips.lst }
|
||||
notify: Restart haproxy
|
||||
|
||||
- name: Render well-known files
|
||||
ansible.builtin.template:
|
||||
src: "haproxy/well-known/{{ item }}.j2"
|
||||
dest: "{{ ess_compose_conf_dir }}/haproxy/well-known/{{ item }}"
|
||||
mode: "0644"
|
||||
loop:
|
||||
- server
|
||||
- client
|
||||
- support
|
||||
- element.json
|
||||
notify: Restart haproxy
|
||||
|
||||
- name: Render Synapse configs
|
||||
ansible.builtin.template:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ ess_compose_conf_dir }}/synapse/{{ item.dest }}"
|
||||
mode: "0640"
|
||||
loop:
|
||||
- { src: synapse/homeserver.yaml.j2, dest: homeserver.yaml }
|
||||
- { src: synapse/log_config.yaml.j2, dest: log_config.yaml }
|
||||
- { src: synapse/federation-reader.yaml.j2, dest: federation-reader.yaml }
|
||||
no_log: true
|
||||
notify:
|
||||
- Restart synapse-main
|
||||
- Restart synapse-fed-reader
|
||||
|
||||
- name: Render MAS config
|
||||
ansible.builtin.template:
|
||||
src: mas/config.yaml.j2
|
||||
dest: "{{ ess_compose_conf_dir }}/mas/config.yaml"
|
||||
mode: "0640"
|
||||
no_log: true
|
||||
notify: Restart mas
|
||||
|
||||
- name: Render SFU config
|
||||
ansible.builtin.template:
|
||||
src: sfu/config.yaml.j2
|
||||
dest: "{{ ess_compose_conf_dir }}/sfu/config.yaml"
|
||||
mode: "0640"
|
||||
no_log: true
|
||||
notify: Restart matrix-rtc-sfu
|
||||
|
||||
- name: Render Element Web config
|
||||
ansible.builtin.template:
|
||||
src: element-web/config.json.j2
|
||||
dest: "{{ ess_compose_conf_dir }}/element-web/config.json"
|
||||
mode: "0644"
|
||||
notify: Restart element-web
|
||||
|
||||
- name: Render Postgres init script
|
||||
ansible.builtin.template:
|
||||
src: postgres/configure-dbs.sh.j2
|
||||
dest: "{{ ess_compose_conf_dir }}/postgres/configure-dbs.sh"
|
||||
mode: "0755"
|
||||
|
||||
- name: Render Redis config
|
||||
ansible.builtin.template:
|
||||
src: redis/redis.conf.j2
|
||||
dest: "{{ ess_compose_conf_dir }}/redis/redis.conf"
|
||||
mode: "0644"
|
||||
notify: Restart redis
|
||||
24
roles/ess_pro_compose/tasks/deploy.yml
Normal file
24
roles/ess_pro_compose/tasks/deploy.yml
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# SPDX-License-Identifier: MIT-0
|
||||
---
|
||||
- name: Render compose project file
|
||||
ansible.builtin.template:
|
||||
src: compose.yml.j2
|
||||
dest: "{{ _ess_compose_file }}"
|
||||
mode: "0640"
|
||||
|
||||
- name: Pull all images
|
||||
community.docker.docker_compose_v2_pull:
|
||||
project_src: "{{ ess_compose_dir }}"
|
||||
register: ess_pull_result
|
||||
|
||||
- name: Bring the stack up
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ ess_compose_dir }}"
|
||||
state: present
|
||||
wait: true
|
||||
wait_timeout: 300
|
||||
register: ess_up_result
|
||||
|
||||
- name: Show running services
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ ess_up_result.services | default([]) | map(attribute='Service') | list }}"
|
||||
39
roles/ess_pro_compose/tasks/main.yml
Normal file
39
roles/ess_pro_compose/tasks/main.yml
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
# SPDX-License-Identifier: MIT-0
|
||||
---
|
||||
- name: Validate required variables
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ess_server_name | length > 0
|
||||
- ess_registry_username | length > 0
|
||||
- ess_registry_token | length > 0
|
||||
- ess_rtc_external_ip | length > 0
|
||||
fail_msg: >-
|
||||
Required variables are missing. Provide ess_server_name,
|
||||
ess_registry_username, ess_registry_token (OpenBao) and
|
||||
ess_rtc_external_ip in group_vars/ess_servers.yml.
|
||||
quiet: true
|
||||
|
||||
- name: Validate OIDC variables when OIDC is enabled
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ess_oidc_issuer | length > 0
|
||||
- ess_oidc_client_secret | length > 0
|
||||
fail_msg: OIDC enabled but issuer / client_secret missing.
|
||||
quiet: true
|
||||
when: ess_oidc_enabled | bool
|
||||
|
||||
- name: Prerequisites (docker, networks, dirs, registry login)
|
||||
ansible.builtin.import_tasks: prereq.yml
|
||||
|
||||
- name: Generate / verify the ess-generated secret bundle
|
||||
ansible.builtin.import_tasks: secrets.yml
|
||||
|
||||
- name: Render all component configuration files
|
||||
ansible.builtin.import_tasks: config.yml
|
||||
|
||||
- name: Render compose project file and start the stack
|
||||
ansible.builtin.import_tasks: deploy.yml
|
||||
|
||||
- name: Post-install (create admin user)
|
||||
ansible.builtin.import_tasks: postinstall.yml
|
||||
when: ess_create_admin_user | bool
|
||||
48
roles/ess_pro_compose/tasks/postinstall.yml
Normal file
48
roles/ess_pro_compose/tasks/postinstall.yml
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
# SPDX-License-Identifier: MIT-0
|
||||
---
|
||||
# Create @localadmin via mas-cli, using the ADMIN_USER_PASSWORD generated
|
||||
# by secrets.yml. Idempotent: mas-cli rejects duplicates, we ignore that.
|
||||
|
||||
- name: Read generated admin password
|
||||
ansible.builtin.slurp:
|
||||
src: "{{ ess_compose_secrets_dir }}/ADMIN_USER_PASSWORD"
|
||||
register: _ess_admin_pw_slurp
|
||||
no_log: true
|
||||
|
||||
- name: Check whether the admin user already exists
|
||||
ansible.builtin.command:
|
||||
cmd: >
|
||||
docker compose -f {{ _ess_compose_file }}
|
||||
exec -T mas
|
||||
mas-cli --config /conf/mas-config.yaml
|
||||
manage list-users --filter username={{ ess_admin_localpart }}
|
||||
register: _ess_admin_check
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Register admin user (mas-cli)
|
||||
ansible.builtin.command:
|
||||
cmd: >
|
||||
docker compose -f {{ _ess_compose_file }}
|
||||
exec -T mas
|
||||
mas-cli --config /conf/mas-config.yaml
|
||||
manage register-user --yes
|
||||
--password {{ (_ess_admin_pw_slurp.content | b64decode).strip() | quote }}
|
||||
--admin
|
||||
{{ ess_admin_localpart }}
|
||||
register: _ess_admin_create
|
||||
changed_when: "'created' in (_ess_admin_create.stdout + _ess_admin_create.stderr) | lower"
|
||||
failed_when:
|
||||
- _ess_admin_create.rc != 0
|
||||
- "'already exists' not in (_ess_admin_create.stdout + _ess_admin_create.stderr) | lower"
|
||||
no_log: true
|
||||
when: ess_admin_localpart not in _ess_admin_check.stdout
|
||||
|
||||
- name: Login hint
|
||||
ansible.builtin.debug:
|
||||
msg: |
|
||||
Stack is up.
|
||||
Admin user: @{{ ess_admin_localpart }}:{{ ess_server_name }}
|
||||
Password is in {{ ess_compose_secrets_dir }}/ADMIN_USER_PASSWORD on this host.
|
||||
Element Web: https://{{ ess_hostnames.element_web }}
|
||||
Element Admin: https://{{ ess_hostnames.element_admin }}
|
||||
45
roles/ess_pro_compose/tasks/prereq.yml
Normal file
45
roles/ess_pro_compose/tasks/prereq.yml
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
# SPDX-License-Identifier: MIT-0
|
||||
---
|
||||
- name: Ensure prerequisite packages on the control target
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- ca-certificates
|
||||
- python3-docker
|
||||
- python3-cryptography
|
||||
state: present
|
||||
update_cache: true
|
||||
|
||||
- name: Verify docker compose plugin is available
|
||||
ansible.builtin.command: docker compose version
|
||||
register: ess_compose_check
|
||||
changed_when: false
|
||||
failed_when: ess_compose_check.rc != 0
|
||||
|
||||
- name: Create project directory tree
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
mode: "0750"
|
||||
owner: root
|
||||
group: root
|
||||
loop: "{{ _ess_dirs }}"
|
||||
|
||||
- name: Tighten secrets directory permissions
|
||||
ansible.builtin.file:
|
||||
path: "{{ ess_compose_secrets_dir }}"
|
||||
state: directory
|
||||
mode: "0700"
|
||||
owner: root
|
||||
group: root
|
||||
|
||||
- name: Ensure the external Traefik proxy network exists
|
||||
community.docker.docker_network:
|
||||
name: "{{ ess_compose_traefik_network }}"
|
||||
state: present
|
||||
|
||||
- name: Authenticate against the Element container registry
|
||||
community.docker.docker_login:
|
||||
registry_url: "{{ ess_registry_url }}"
|
||||
username: "{{ ess_registry_username }}"
|
||||
password: "{{ ess_registry_token }}"
|
||||
no_log: true
|
||||
47
roles/ess_pro_compose/tasks/secrets.yml
Normal file
47
roles/ess_pro_compose/tasks/secrets.yml
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
# SPDX-License-Identifier: MIT-0
|
||||
---
|
||||
# Generate the ess-generated secret bundle. Mirrors the chart's `init-secrets`
|
||||
# job, but runs locally on the host. Idempotent — only writes missing files.
|
||||
|
||||
- name: Render generate-secrets script
|
||||
ansible.builtin.template:
|
||||
src: generate-secrets.py.j2
|
||||
dest: "{{ ess_compose_dir }}/.generate-secrets.py"
|
||||
mode: "0700"
|
||||
|
||||
- name: Run generate-secrets (creates only what's missing)
|
||||
ansible.builtin.command:
|
||||
cmd: "/usr/bin/python3 {{ ess_compose_dir }}/.generate-secrets.py"
|
||||
register: ess_secrets_run
|
||||
changed_when: "'CREATED:' in ess_secrets_run.stdout"
|
||||
|
||||
- name: Verify every required secret exists
|
||||
ansible.builtin.stat:
|
||||
path: "{{ ess_compose_secrets_dir }}/{{ item }}"
|
||||
register: ess_secret_stat
|
||||
loop: "{{ _ess_secret_names }}"
|
||||
failed_when: not ess_secret_stat.stat.exists
|
||||
|
||||
- name: Read postgres passwords for config templates (not persisted)
|
||||
ansible.builtin.slurp:
|
||||
src: "{{ ess_compose_secrets_dir }}/{{ item }}"
|
||||
register: ess_password_slurp
|
||||
loop:
|
||||
- POSTGRES_ADMIN_PASSWORD
|
||||
- POSTGRES_SYNAPSE_PASSWORD
|
||||
- POSTGRES_MATRIX_AUTHENTICATION_SERVICE_PASSWORD
|
||||
- SYNAPSE_MACAROON
|
||||
- SYNAPSE_REGISTRATION_SHARED_SECRET
|
||||
- SYNAPSE_WORKERS_REPLICATION_SECRET
|
||||
- MAS_SYNAPSE_SHARED_SECRET
|
||||
- MAS_MATRIX_TOOLS_OIDC_CLIENT_SECRET
|
||||
- ELEMENT_CALL_LIVEKIT_SECRET
|
||||
no_log: true
|
||||
|
||||
- name: Expose passwords as facts for templates
|
||||
ansible.builtin.set_fact:
|
||||
_ess_secrets: "{{ _ess_secrets | default({}) | combine({item.item: (item.content | b64decode).strip()}) }}"
|
||||
loop: "{{ ess_password_slurp.results }}"
|
||||
loop_control:
|
||||
label: "{{ item.item }}"
|
||||
no_log: true
|
||||
Loading…
Add table
Add a link
Reference in a new issue