From 6594cce57038c5118e9b056f2b2c0b4ec9451b93 Mon Sep 17 00:00:00 2001 From: wjbeckett Date: Wed, 25 Sep 2024 14:53:48 +1000 Subject: [PATCH] Feat: Added element call setup and configuration. --- docs/configuring-playbook-element-call.md | 74 ++++++++ group_vars/matrix_servers | 58 +++++++ .../matrix-element-call/defaults/main.yml | 34 ++++ .../tasks/create_element_json.yml | 22 +++ .../matrix-element-call/tasks/install.yml | 17 ++ .../tasks/install_docker_containers.yml | 158 ++++++++++++++++++ .../custom/matrix-element-call/tasks/main.yml | 14 ++ .../matrix-element-call/tasks/uninstall.yml | 51 ++++++ .../tasks/update_element_web_config.yml | 29 ++++ .../tasks/update_homeserver_config.yml | 36 ++++ .../tasks/update_well_known_client.yml | 24 +++ .../tasks/validate_config.yml | 79 +++++++++ .../templates/config.json.j2 | 11 ++ .../matrix-element-call/templates/env.j2 | 9 + .../matrix-element-call/templates/labels.j2 | 11 ++ .../templates/livekit.yaml.j2 | 21 +++ .../templates/redis.conf.j2 | 5 + .../systemd/matrix-element-call.service.j2 | 17 ++ .../custom/matrix-element-call/vars/main.yml | 5 + setup.yml | 1 + 20 files changed, 676 insertions(+) create mode 100644 docs/configuring-playbook-element-call.md create mode 100644 roles/custom/matrix-element-call/defaults/main.yml create mode 100644 roles/custom/matrix-element-call/tasks/create_element_json.yml create mode 100644 roles/custom/matrix-element-call/tasks/install.yml create mode 100644 roles/custom/matrix-element-call/tasks/install_docker_containers.yml create mode 100644 roles/custom/matrix-element-call/tasks/main.yml create mode 100644 roles/custom/matrix-element-call/tasks/uninstall.yml create mode 100644 roles/custom/matrix-element-call/tasks/update_element_web_config.yml create mode 100644 roles/custom/matrix-element-call/tasks/update_homeserver_config.yml create mode 100644 roles/custom/matrix-element-call/tasks/update_well_known_client.yml create mode 100644 roles/custom/matrix-element-call/tasks/validate_config.yml create mode 100644 roles/custom/matrix-element-call/templates/config.json.j2 create mode 100644 roles/custom/matrix-element-call/templates/env.j2 create mode 100644 roles/custom/matrix-element-call/templates/labels.j2 create mode 100644 roles/custom/matrix-element-call/templates/livekit.yaml.j2 create mode 100644 roles/custom/matrix-element-call/templates/redis.conf.j2 create mode 100644 roles/custom/matrix-element-call/templates/systemd/matrix-element-call.service.j2 create mode 100644 roles/custom/matrix-element-call/vars/main.yml diff --git a/docs/configuring-playbook-element-call.md b/docs/configuring-playbook-element-call.md new file mode 100644 index 000000000..bd36357ab --- /dev/null +++ b/docs/configuring-playbook-element-call.md @@ -0,0 +1,74 @@ +# Setting up Element Call (optional) + +The playbook can install and configure [Element Call](https://github.com/vector-im/element-call) for you. + +Element Call is a WebRTC-based video and voice calling platform that integrates with Matrix clients such as Element Web. It provides secure, decentralized communication with support for video calls, audio calls, and screen sharing. + +See the project's [documentation](https://github.com/vector-im/element-call) to learn more. + +## Decide on a domain and path + +By default, Element Call is configured to be served on the Matrix domain (`call.DOMAIN`, controlled by the `matrix_element_call_hostname` variable). + +This makes it easy to set it up, **without** having to adjust your DNS records manually. + +If you'd like to run Element Call on another hostname or path, use the `matrix_element_call_hostname` and `matrix_element_call_path_prefix` variables. + +## Adjusting DNS records + +If you've changed the default hostname, **you may need to adjust your DNS** records accordingly to point to the correct server. + +Ensure that the following DNS names have a public IP/FQDN: +- `call.DOMAIN` +- `sfu.DOMAIN` +- `sfu-jwt.DOMAIN` + +## Adjusting the playbook configuration + +Add the following configuration to your `inventory/host_vars/matrix.DOMAIN/vars.yml` file: + +```yaml +matrix_element_call_enabled: true +# Set a secure key for LiveKit authentication +matrix_element_call_livekit_dev_key: 'your-secure-livekit-key' +``` + +## External databases + +If your setup utilizes an external database, you may need to adjust the default configuration for Redis used by Element Call. Modify the defaults in group_vars/matrix_servers.yml or host_vars to suit your setup: + +```yaml +matrix_element_call_redis_hostname: 'localhost' +matrix_element_call_redis_port: 6379 +matrix_element_call_redis_password: '' +``` + +## Installing +After potentially adjusting DNS records and configuring the playbook, run the installation command again: +```yaml +ansible-playbook -i inventory setup.yml +``` + +## Usage +Once installed, Element Call integrates seamlessly with Matrix clients like Element Web. When the Element Call service is installed, the `/.well-known/matrix/client` file is also updated. A new `org.matrix.msc4143.rtc_foci` section is added to point to your JWT service URL (e.g., `https://sfu-jwt.DOMAIN`). + +Additionally, the `/.well-known/element/element.json` file is created to help Element clients discover the Element Call URL (e.g., `https://call.DOMAIN`). + +## Required Firewall and Port Forwarding Rules + +To ensure the services function correctly, the following firewall rules and port forwarding settings are required: + +LiveKit: + + • Forward UDP ports 50100:50200 to the Docker instance running LiveKit. + • Forward TCP port 7881 to the Docker instance running LiveKit. + +Element Call: + + • Forward TCP port 443 to the server running Traefik (for Element Call). + +Ensure these ports are open and forwarded appropriately to allow traffic to flow correctly between the services. + +## Additional Information + +Refer to the Element Call documentation for more details on configuring and using Element Call. \ No newline at end of file diff --git a/group_vars/matrix_servers b/group_vars/matrix_servers index c6682be41..58e93c7b2 100755 --- a/group_vars/matrix_servers +++ b/group_vars/matrix_servers @@ -5690,3 +5690,61 @@ devture_traefik_certs_dumper_ssl_dir_path: "{{ devture_traefik_ssl_dir_path if d # /com.devture.ansible.role.traefik_certs_dumper # # # ######################################################################## + + +######################################################################## +# # +# matrix-element-call # +# # +######################################################################## + +# Matrix Element Call Configuration +matrix_element_call_enabled: false # Default is false; should be enabled in host_vars as needed +matrix_element_call_version: "latest" # Default version; can be overridden in host_vars +matrix_element_call_scheme: "https" # Scheme for Element Call (e.g., https) +matrix_element_call_hostname: "call.{{ matrix_domain }}" # Default hostname; should be overridden in host_vars if different +matrix_element_call_path_prefix: "/" # Path prefix for Element Call +matrix_element_call_base_path: "{{ matrix_base_data_path }}/element-call" # Base path for storing Element Call-related files +matrix_element_call_container_image: "ghcr.io/element-hq/element-call:{{ matrix_element_call_version }}" +matrix_element_call_container_image_name_prefix: ghcr.io/ +matrix_element_call_container_image_registry_prefix: ghcr.io/ +matrix_element_call_container_image_force_pull: true + +# Docker network configuration for Element Call +matrix_element_call_container_network: "{{ matrix_homeserver_container_network }}" # Use the homeserver network by default + +# Traefik Configuration for Element Call +matrix_element_call_container_labels_traefik_enabled: true +matrix_element_call_container_labels_traefik_hostname: "{{ matrix_element_call_hostname }}" +matrix_element_call_container_labels_traefik_path_prefix: "{{ matrix_element_call_path_prefix }}" +matrix_element_call_container_labels_traefik_rule: "Host(`{{ matrix_element_call_container_labels_traefik_hostname }}`)" +matrix_element_call_container_labels_traefik_entrypoints: "websecure" +matrix_element_call_container_labels_traefik_tls_certResolver: "default" + +# JWT Service Configuration +matrix_element_call_jwt_service_url: "https://sfu-jwt.{{ matrix_domain }}" # Default JWT service URL; adjust as needed + +# LiveKit Service Configuration +matrix_element_call_livekit_service_url: "https://sfu.{{ matrix_domain }}" # Default LiveKit service URL; adjust as needed +matrix_element_call_livekit_dev_key: "{{ matrix_livekit_dev_key }}" # LiveKit dev key + +# Redis Configuration for Element Call +matrix_element_call_redis_hostname: "localhost" # Default Redis hostname; can be overridden +matrix_element_call_redis_port: 6379 # Default Redis port; can be overridden +matrix_element_call_redis_password: "" # Redis password; should be set in host_vars if needed + +# Additional environment variables for the container +matrix_element_call_environment_variables_additional: {} + +# Additional arguments or configuration options for the Docker container +matrix_element_call_container_extra_arguments: [] + +# Enable or disable metrics collection +matrix_element_call_metrics_enabled: false +matrix_element_call_metrics_port: 2112 + +######################################################################## +# # +# /matrix-element-call # +# # +######################################################################## \ No newline at end of file diff --git a/roles/custom/matrix-element-call/defaults/main.yml b/roles/custom/matrix-element-call/defaults/main.yml new file mode 100644 index 000000000..38b175532 --- /dev/null +++ b/roles/custom/matrix-element-call/defaults/main.yml @@ -0,0 +1,34 @@ +--- +# roles/custom/matrix-element-call/defaults/main.yml + +# Enable or disable matrix-element-call deployment +matrix_element_call_enabled: false + +# Base path configuration +matrix_element_call_base_path: "/home/{{ matrix_user_username }}/dockerdata/volumes/elementcall" +matrix_element_call_config_path: "{{ matrix_element_call_base_path }}/config" +matrix_element_call_backend_path: "{{ matrix_element_call_base_path }}/backend" + +# Docker network configuration +matrix_element_call_container_network: "matrix_element_call_network" + +# Docker images +matrix_element_call_image: "ghcr.io/element-hq/element-call:latest" +matrix_jwt_service_image: "ghcr.io/element-hq/lk-jwt-service:latest-ci" +matrix_livekit_image: "livekit/livekit-server:latest" +matrix_redis_image: "redis:6-alpine" + +# Ports +matrix_element_call_port: "8093" +matrix_jwt_service_port: "8881" +matrix_redis_port: "6379" + +# LiveKit configuration (should be set in host_vars or globally) +matrix_element_call_livekit_dev_key: "{{ matrix_livekit_dev_key | default('unset-livekit-key') }}" +matrix_element_call_livekit_service_url: "wss://sfu.{{ matrix_base_domain }}:443" + +# Well-known paths and domains (derived from matrix_base_domain) +matrix_element_call_domain: "call.{{ matrix_base_domain }}" +matrix_element_call_well_known_client_path: "/var/www/.well-known/matrix/client" +matrix_element_call_well_known_element_path: "/var/www/.well-known/element/element.json" +matrix_element_call_base_url: "https://{{ matrix_element_call_domain }}" \ No newline at end of file diff --git a/roles/custom/matrix-element-call/tasks/create_element_json.yml b/roles/custom/matrix-element-call/tasks/create_element_json.yml new file mode 100644 index 000000000..7fe689183 --- /dev/null +++ b/roles/custom/matrix-element-call/tasks/create_element_json.yml @@ -0,0 +1,22 @@ +--- +--- +# Create the element.json file to point to Element Call + +- name: Ensure .well-known/element directory exists + ansible.builtin.file: + path: "{{ matrix_element_call_well_known_element_path | dirname }}" + state: directory + mode: 0755 + +- name: Create or update the element.json file with Element Call config + ansible.builtin.copy: + dest: "{{ matrix_element_call_well_known_element_path }}" + content: | + { + "call": { + "widget_url": "{{ matrix_element_call_base_url }}" + } + } + mode: '0644' + owner: "{{ matrix_user_username }}" + group: "{{ matrix_user_groupname }}" \ No newline at end of file diff --git a/roles/custom/matrix-element-call/tasks/install.yml b/roles/custom/matrix-element-call/tasks/install.yml new file mode 100644 index 000000000..250f8c093 --- /dev/null +++ b/roles/custom/matrix-element-call/tasks/install.yml @@ -0,0 +1,17 @@ +--- +# Main install task for matrix-element-call + +- name: Install Docker containers for Element Call + include_tasks: install_docker_containers.yml + +- name: Update .well-known/matrix/client + include_tasks: update_well_known_client.yml + +- name: Create .well-known/element/element.json + include_tasks: create_element_json.yml + +- name: Update homeserver.yaml for Element Call + include_tasks: update_homeserver_config.yml + +- name: Update Element-Web config.json for Element Call + include_tasks: update_element_web_config.yml \ No newline at end of file diff --git a/roles/custom/matrix-element-call/tasks/install_docker_containers.yml b/roles/custom/matrix-element-call/tasks/install_docker_containers.yml new file mode 100644 index 000000000..38dfbbd70 --- /dev/null +++ b/roles/custom/matrix-element-call/tasks/install_docker_containers.yml @@ -0,0 +1,158 @@ +--- +# Ensure Required Directories Exist +- name: Ensure matrix-element-call paths exist + ansible.builtin.file: + path: "{{ item.path }}" + state: directory + mode: 0750 + owner: "{{ matrix_user_username }}" + group: "{{ matrix_user_groupname }}" + loop: + - path: "{{ matrix_element_call_base_path }}" + - path: "{{ matrix_element_call_base_path }}/data" + - path: "{{ matrix_element_call_base_path }}/config" + - path: "{{ matrix_element_call_base_path }}/backend" # For LiveKit and Redis config + +# Ensure Configuration Files are in Place +- name: Ensure Element Call config.json is in place + ansible.builtin.template: + src: "{{ role_path }}/templates/config.json.j2" + dest: "{{ matrix_element_call_base_path }}/config/config.json" + mode: 0640 + owner: "{{ matrix_user_username }}" + group: "{{ matrix_user_groupname }}" + +- name: Ensure LiveKit livekit.yaml is in place + ansible.builtin.template: + src: "{{ role_path }}/templates/livekit.yaml.j2" + dest: "{{ matrix_element_call_base_path }}/backend/livekit.yaml" + mode: 0640 + owner: "{{ matrix_user_username }}" + group: "{{ matrix_user_groupname }}" + +- name: Ensure Redis redis.conf is in place + ansible.builtin.template: + src: "{{ role_path }}/templates/redis.conf.j2" + dest: "{{ matrix_element_call_base_path }}/backend/redis.conf" + mode: 0640 + owner: "{{ matrix_user_username }}" + group: "{{ matrix_user_groupname }}" + +- name: Ensure matrix-element-call environment file is in place + ansible.builtin.template: + src: "{{ role_path }}/templates/env.j2" + dest: "{{ matrix_element_call_base_path }}/config/env" + mode: 0640 + owner: "{{ matrix_user_username }}" + group: "{{ matrix_user_groupname }}" + +- name: Ensure matrix-element-call Docker labels file is in place + ansible.builtin.template: + src: "{{ role_path }}/templates/labels.j2" + dest: "{{ matrix_element_call_base_path }}/config/labels" + mode: 0640 + owner: "{{ matrix_user_username }}" + group: "{{ matrix_user_groupname }}" + +# Ensure Docker Images are Pulled +- name: Ensure matrix-element-call Docker image is pulled + community.docker.docker_image: + name: "{{ matrix_element_call_image }}" + source: pull + force_source: "{{ matrix_element_call_container_image_force_pull }}" + register: element_call_image_result + retries: "{{ devture_playbook_help_container_retries_count }}" + delay: "{{ devture_playbook_help_container_retries_delay }}" + until: element_call_image_result is not failed + +- name: Ensure jwt-service Docker image is pulled + community.docker.docker_image: + name: "ghcr.io/element-hq/lk-jwt-service:latest-ci" + source: pull + register: jwt_image_result + retries: 3 + delay: 10 + until: jwt_image_result is not failed + +- name: Ensure livekit Docker image is pulled + community.docker.docker_image: + name: "livekit/livekit-server:latest" + source: pull + register: livekit_image_result + retries: 3 + delay: 10 + until: livekit_image_result is not failed + +- name: Ensure redis Docker image is pulled + community.docker.docker_image: + name: "redis:6-alpine" + source: pull + register: redis_image_result + retries: 3 + delay: 10 + until: redis_image_result is not failed + +# Ensure Docker Containers are Running +- name: Run matrix-element-call Docker container + community.docker.docker_container: + name: "matrix-element-call" + image: "{{ matrix_element_call_image }}" + state: started + restart_policy: unless-stopped + env_file: "{{ matrix_element_call_base_path }}/config/env" + labels: "{{ lookup('file', matrix_element_call_base_path ~ '/config/labels') | from_yaml }}" + networks: + - name: "{{ matrix_element_call_container_network }}" + volumes: + - "{{ matrix_element_call_base_path }}/config/config.json:/app/config.json" + - "{{ matrix_element_call_base_path }}/data:/data" + +- name: Run jwt-service Docker container + community.docker.docker_container: + name: "matrix-jwt-service" + image: "ghcr.io/element-hq/lk-jwt-service:latest-ci" + state: started + restart_policy: unless-stopped + environment: + LIVEKIT_SECRET: "{{ matrix_element_call_livekit_dev_key }}" # User-specified key + LIVEKIT_URL: "{{ matrix_element_call_livekit_service_url }}" + LIVEKIT_KEY: "devkey" + networks: + - name: "{{ matrix_element_call_container_network }}" + +- name: Run livekit Docker container + community.docker.docker_container: + name: "matrix-livekit" + image: "livekit/livekit-server:latest" + state: started + restart_policy: unless-stopped + command: "--dev --config /etc/livekit.yaml" + volumes: + - "{{ matrix_element_call_base_path }}/backend/livekit.yaml:/etc/livekit.yaml" + network_mode: "host" + +- name: Run redis Docker container + community.docker.docker_container: + name: "matrix-redis" + image: "redis:6-alpine" + state: started + restart_policy: unless-stopped + command: redis-server /etc/redis.conf + volumes: + - "{{ matrix_element_call_base_path }}/backend/redis.conf:/etc/redis.conf" + networks: + - name: "{{ matrix_element_call_container_network }}" + +# Ensure Systemd Services are Set Up +- name: Ensure matrix-element-call systemd service is installed + ansible.builtin.template: + src: "{{ role_path }}/templates/element-call.service.j2" + dest: "{{ devture_systemd_docker_base_systemd_path }}/matrix-element-call.service" + mode: 0644 + +- name: Ensure matrix-element-call systemd service is enabled and started + ansible.builtin.systemd: + name: matrix-element-call + enabled: true + state: started + daemon_reload: true \ No newline at end of file diff --git a/roles/custom/matrix-element-call/tasks/main.yml b/roles/custom/matrix-element-call/tasks/main.yml new file mode 100644 index 000000000..ae0f7ce68 --- /dev/null +++ b/roles/custom/matrix-element-call/tasks/main.yml @@ -0,0 +1,14 @@ +--- +# roles/custom/matrix-element-call/tasks/main.yml + +- name: Ensure Element Call dependencies are valid and present + when: matrix_element_call_enabled | bool + ansible.builtin.include_tasks: "{{ role_path }}/tasks/validate_config.yml" + +- name: Install Element Call and its related services + when: matrix_element_call_enabled | bool + ansible.builtin.include_tasks: "{{ role_path }}/tasks/install.yml" + +- name: Uninstall Element Call and clean up resources + when: not matrix_element_call_enabled | bool + ansible.builtin.include_tasks: "{{ role_path }}/tasks/uninstall.yml" \ No newline at end of file diff --git a/roles/custom/matrix-element-call/tasks/uninstall.yml b/roles/custom/matrix-element-call/tasks/uninstall.yml new file mode 100644 index 000000000..f863c25be --- /dev/null +++ b/roles/custom/matrix-element-call/tasks/uninstall.yml @@ -0,0 +1,51 @@ +--- +--- +# roles/custom/matrix-element-call/tasks/uninstall.yml + +# Stop and remove Docker containers +- name: Stop and remove matrix-element-call Docker container + community.docker.docker_container: + name: "matrix-element-call" + state: absent + when: matrix_element_call_enabled | bool == false + +- name: Stop and remove jwt-service Docker container + community.docker.docker_container: + name: "matrix-jwt-service" + state: absent + when: matrix_element_call_enabled | bool == false + +- name: Stop and remove livekit Docker container + community.docker.docker_container: + name: "matrix-livekit" + state: absent + when: matrix_element_call_enabled | bool == false + +- name: Stop and remove redis Docker container + community.docker.docker_container: + name: "matrix-redis" + state: absent + when: matrix_element_call_enabled | bool == false + +# Remove matrix-element-call directories +- name: Remove matrix-element-call directories + ansible.builtin.file: + path: "{{ item }}" + state: absent + loop: + - "{{ matrix_element_call_base_path }}" + when: matrix_element_call_enabled | bool == false + +# Disable and remove systemd service for matrix-element-call +- name: Stop and disable matrix-element-call systemd service + ansible.builtin.systemd: + name: matrix-element-call + state: stopped + enabled: false + when: matrix_element_call_enabled | bool == false + +- name: Remove matrix-element-call systemd service file + ansible.builtin.file: + path: "{{ devture_systemd_docker_base_systemd_path }}/matrix-element-call.service" + state: absent + when: matrix_element_call_enabled | bool == false \ No newline at end of file diff --git a/roles/custom/matrix-element-call/tasks/update_element_web_config.yml b/roles/custom/matrix-element-call/tasks/update_element_web_config.yml new file mode 100644 index 000000000..0fa227172 --- /dev/null +++ b/roles/custom/matrix-element-call/tasks/update_element_web_config.yml @@ -0,0 +1,29 @@ +--- +# Update Element-Web config.json with Element Call features + +- name: Ensure Element-Web config.json exists + ansible.builtin.file: + path: "{{ matrix_element_web_config_path }}" + state: file + mode: 0644 + +- name: Update Element-Web config.json with Element Call features + ansible.builtin.blockinfile: + path: "{{ matrix_element_web_config_path }}" + block: | + "features": { + "feature_video_rooms": true, + "feature_new_room_decoration_ui": true, + "feature_group_calls": true, + "feature_element_call_video_rooms": true + }, + "element_call": { + "url": "{{ matrix_element_call_base_url }}", + "participant_limit": 8, + "brand": "Element Call", + "use_exclusively": true + } + marker: "# ANSIBLE MANAGED BLOCK - Element Call features" + mode: '0644' + owner: "{{ matrix_user_username }}" + group: "{{ matrix_user_groupname }}" \ No newline at end of file diff --git a/roles/custom/matrix-element-call/tasks/update_homeserver_config.yml b/roles/custom/matrix-element-call/tasks/update_homeserver_config.yml new file mode 100644 index 000000000..46e4f5a09 --- /dev/null +++ b/roles/custom/matrix-element-call/tasks/update_homeserver_config.yml @@ -0,0 +1,36 @@ +--- +# Update the homeserver.yaml file with Element Call config + +- name: Ensure homeserver.yaml exists + ansible.builtin.file: + path: "{{ matrix_homeserver_config_path }}" + state: file + mode: 0644 + +- name: Add listeners section for Element Call to homeserver.yaml + ansible.builtin.blockinfile: + path: "{{ matrix_homeserver_config_path }}" + block: | + listeners: + - port: 8008 + tls: false + type: http + x_forwarded: true + + resources: + - names: [client, federation, openid] + compress: false + marker: "# ANSIBLE MANAGED BLOCK - Element Call listeners" + mode: '0644' + owner: "{{ matrix_user_username }}" + group: "{{ matrix_user_groupname }}" + +- name: Ensure serve_server_wellknown is enabled in homeserver.yaml + ansible.builtin.lineinfile: + path: "{{ matrix_homeserver_config_path }}" + line: "serve_server_wellknown: true" + insertafter: EOF + state: present + mode: '0644' + owner: "{{ matrix_user_username }}" + group: "{{ matrix_user_groupname }}" \ No newline at end of file diff --git a/roles/custom/matrix-element-call/tasks/update_well_known_client.yml b/roles/custom/matrix-element-call/tasks/update_well_known_client.yml new file mode 100644 index 000000000..b02269f1c --- /dev/null +++ b/roles/custom/matrix-element-call/tasks/update_well_known_client.yml @@ -0,0 +1,24 @@ +--- +--- +# Update the .well-known/matrix/client file with Element Call config + +- name: Ensure .well-known directory exists + ansible.builtin.file: + path: "{{ matrix_element_call_well_known_client_path | dirname }}" + state: directory + mode: 0755 + +- name: Update .well-known/matrix/client file with Element Call config + ansible.builtin.blockinfile: + path: "{{ matrix_element_call_well_known_client_path }}" + block: | + "org.matrix.msc4143.rtc_foci": [ + { + "type": "livekit", + "livekit_service_url": "{{ matrix_element_call_jwt_service_url }}" + } + ] + create: yes + mode: '0644' + owner: "{{ matrix_user_username }}" + group: "{{ matrix_user_groupname }}" \ No newline at end of file diff --git a/roles/custom/matrix-element-call/tasks/validate_config.yml b/roles/custom/matrix-element-call/tasks/validate_config.yml new file mode 100644 index 000000000..c4a55e0df --- /dev/null +++ b/roles/custom/matrix-element-call/tasks/validate_config.yml @@ -0,0 +1,79 @@ +--- +# roles/custom/matrix-element-call/tasks/validate_config.yml + +- name: Ensure required variables for Element Call are defined + ansible.builtin.fail: + msg: "The variable '{{ item }}' is required and must be set." + when: vars[item] is not defined or vars[item] == '' + loop: + - matrix_element_call_enabled + - matrix_element_call_version + - matrix_element_call_hostname + - matrix_element_call_path_prefix + - matrix_element_call_base_path + - matrix_element_call_container_image + - matrix_element_call_container_network + - matrix_element_call_container_labels_traefik_hostname + - matrix_element_call_jwt_service_url + - matrix_element_call_livekit_service_url + - matrix_element_call_livekit_dev_key + +- name: Validate that the Element Call hostname is properly formatted + ansible.builtin.assert: + that: + - "'{{ matrix_element_call_hostname }}' is match('^([a-zA-Z0-9][-a-zA-Z0-9]*[a-zA-Z0-9])$')" + fail_msg: "The hostname '{{ matrix_element_call_hostname }}' is not valid. It should be a valid domain or subdomain." + success_msg: "The hostname '{{ matrix_element_call_hostname }}' is valid." + +- name: Validate that the Element Call version is specified correctly + ansible.builtin.assert: + that: + - matrix_element_call_version is string + - matrix_element_call_version != '' + fail_msg: "The Element Call version must be a non-empty string." + success_msg: "The Element Call version is set correctly." + +- name: Ensure LiveKit dev key is set + ansible.builtin.assert: + that: + - matrix_element_call_livekit_dev_key is string + - matrix_element_call_livekit_dev_key != '' + fail_msg: "The LiveKit dev key (matrix_element_call_livekit_dev_key) must be a non-empty string." + success_msg: "The LiveKit dev key is set correctly." + +- name: Ensure JWT service URL is valid + ansible.builtin.assert: + that: + - matrix_element_call_jwt_service_url is match('^https?://[a-zA-Z0-9.-]+$') + fail_msg: "The JWT service URL '{{ matrix_element_call_jwt_service_url }}' is not valid." + success_msg: "The JWT service URL is valid." + +- name: Ensure LiveKit service URL is valid + ansible.builtin.assert: + that: + - matrix_element_call_livekit_service_url is match('^https?://[a-zA-Z0-9.-]+$') + fail_msg: "The LiveKit service URL '{{ matrix_element_call_livekit_service_url }}' is not valid." + success_msg: "The LiveKit service URL is valid." + +- name: Ensure matrix-element-call base path is set and exists + ansible.builtin.assert: + that: + - matrix_element_call_base_path is string + - matrix_element_call_base_path != '' + fail_msg: "The base path for Element Call (matrix_element_call_base_path) must be a non-empty string." + success_msg: "The base path for Element Call is set correctly." + +- name: Ensure required paths for configurations are accessible + ansible.builtin.file: + path: "{{ item }}" + state: directory + with_items: + - "{{ matrix_element_call_base_path }}/config" + - "{{ matrix_element_call_base_path }}/backend" + register: config_paths_check + +- name: Fail if any required paths for configurations are not accessible + ansible.builtin.fail: + msg: "The required configuration path '{{ item.path }}' does not exist or is not accessible." + when: config_paths_check.results is defined and config_paths_check.results | selectattr('failed', 'eq', True) | list | length > 0 + loop: "{{ config_paths_check.results | selectattr('failed', 'eq', True) | list }}" \ No newline at end of file diff --git a/roles/custom/matrix-element-call/templates/config.json.j2 b/roles/custom/matrix-element-call/templates/config.json.j2 new file mode 100644 index 000000000..1ce2f57c5 --- /dev/null +++ b/roles/custom/matrix-element-call/templates/config.json.j2 @@ -0,0 +1,11 @@ +{ + "default_server_config": { + "m.homeserver": { + "base_url": "{{ matrix_homeserver_url }}", + "server_name": "{{ matrix_server_name }}" + } + }, + "livekit": { + "livekit_service_url": "{{ matrix_element_call_livekit_service_url }}" + } +} \ No newline at end of file diff --git a/roles/custom/matrix-element-call/templates/env.j2 b/roles/custom/matrix-element-call/templates/env.j2 new file mode 100644 index 000000000..db25ed81b --- /dev/null +++ b/roles/custom/matrix-element-call/templates/env.j2 @@ -0,0 +1,9 @@ +# Environment variables for Element Call +ELEMENT_CALL_SERVER_URL=https://{{ matrix_element_call_domain }} +LIVEKIT_SERVICE_URL={{ matrix_element_call_livekit_service_url }} +JWT_SERVICE_URL={{ matrix_element_call_jwt_service_url }} + +# Optional additional environment variables provided by the user +{% for key, value in matrix_element_call_environment_variables_additional.items() %} +{{ key }}={{ value }} +{% endfor %} \ No newline at end of file diff --git a/roles/custom/matrix-element-call/templates/labels.j2 b/roles/custom/matrix-element-call/templates/labels.j2 new file mode 100644 index 000000000..988bfba1c --- /dev/null +++ b/roles/custom/matrix-element-call/templates/labels.j2 @@ -0,0 +1,11 @@ +# Docker labels for Traefik or other routing +traefik.enable: "true" +traefik.http.routers.{{ matrix_element_call_hostname | replace('.', '_') }}-router.rule: "Host(`{{ matrix_element_call_hostname }}`)" +traefik.http.routers.{{ matrix_element_call_hostname | replace('.', '_') }}-router.entrypoints: "{{ matrix_element_call_container_labels_traefik_entrypoints }}" +traefik.http.routers.{{ matrix_element_call_hostname | replace('.', '_') }}-router.tls.certresolver: "{{ matrix_element_call_container_labels_traefik_tls_certResolver }}" +traefik.http.services.{{ matrix_element_call_hostname | replace('.', '_') }}-service.loadbalancer.server.port: "8080" + +# Additional labels (if any) specified by the user +{% for key, value in matrix_element_call_container_extra_arguments.items() %} +{{ key }}: "{{ value }}" +{% endfor %} \ No newline at end of file diff --git a/roles/custom/matrix-element-call/templates/livekit.yaml.j2 b/roles/custom/matrix-element-call/templates/livekit.yaml.j2 new file mode 100644 index 000000000..a53c0896a --- /dev/null +++ b/roles/custom/matrix-element-call/templates/livekit.yaml.j2 @@ -0,0 +1,21 @@ +port: 7880 +bind_addresses: + - "0.0.0.0" +rtc: + tcp_port: 7881 + port_range_start: 50100 + port_range_end: 50200 + use_external_ip: false + +turn: + enabled: false + domain: localhost + cert_file: "" + key_file: "" + tls_port: 5349 + udp_port: 443 + external_tls: true + +keys: + devkey: "{{ matrix_element_call_livekit_dev_key }}" +logging: \ No newline at end of file diff --git a/roles/custom/matrix-element-call/templates/redis.conf.j2 b/roles/custom/matrix-element-call/templates/redis.conf.j2 new file mode 100644 index 000000000..da19af05a --- /dev/null +++ b/roles/custom/matrix-element-call/templates/redis.conf.j2 @@ -0,0 +1,5 @@ +bind 0.0.0.0 +protected-mode yes +port 6379 +timeout 0 +tcp-keepalive 300 \ No newline at end of file diff --git a/roles/custom/matrix-element-call/templates/systemd/matrix-element-call.service.j2 b/roles/custom/matrix-element-call/templates/systemd/matrix-element-call.service.j2 new file mode 100644 index 000000000..8caad624f --- /dev/null +++ b/roles/custom/matrix-element-call/templates/systemd/matrix-element-call.service.j2 @@ -0,0 +1,17 @@ +[Unit] +Description=Matrix Element Call Service +After=docker.service +Requires=docker.service + +[Service] +Type=simple +ExecStart=/usr/bin/docker start -a matrix-element-call +ExecStop=/usr/bin/docker stop matrix-element-call +Restart=always +User={{ matrix_user_username }} +Group={{ matrix_user_groupname }} +TimeoutStartSec=0 +RestartSec=10 + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/roles/custom/matrix-element-call/vars/main.yml b/roles/custom/matrix-element-call/vars/main.yml new file mode 100644 index 000000000..1f224472a --- /dev/null +++ b/roles/custom/matrix-element-call/vars/main.yml @@ -0,0 +1,5 @@ +--- +# roles/custom/matrix-element-call/vars/main.yml + +# Variables specific to matrix-element-call, like service configurations, can go here. +# Any environment-specific values can be overridden here. \ No newline at end of file diff --git a/setup.yml b/setup.yml index 3cff6dbb1..cbc3e1673 100644 --- a/setup.yml +++ b/setup.yml @@ -130,6 +130,7 @@ - custom/matrix-coturn - custom/matrix-media-repo - custom/matrix-pantalaimon + - custom/matrix-element-call - role: galaxy/postgres_backup