From 38a2d86adcfbaf587d4e3d3cfdc2ad06f30ea2b0 Mon Sep 17 00:00:00 2001 From: Slavi Pantaleev Date: Thu, 16 Mar 2023 11:54:12 +0200 Subject: [PATCH] Initial commit Fix incorrect tag Do not mount timezone files Rocky Linux 9 does not have an `/etc/timezone` file, which begs the question: why even do this? Upgrade (1.27.0 -> 1.28.0) Fixes https://github.com/mother-of-all-self-hosting/mash-playbook/issues/25 Switch from docker.io to ghcr.io Upgrade (1.28.0 -> 1.28.1) and drop NET_BIND_SERVICE workaround Related to: - https://github.com/mother-of-all-self-hosting/mash-playbook/issues/25 - https://github.com/dani-garcia/vaultwarden/discussions/3387 - https://github.com/dani-garcia/vaultwarden/pull/3403 Upgrade (1.28.1 -> 1.29.0) and remove dedicated WebSocket port As per https://github.com/dani-garcia/vaultwarden/pull/3404, we no longer need a dedicated websocket port. Upgrade (1.29.0 -> 1.29.1) Add missing Project source code URL annotation Upgrade (1.29.1 -> 1.29.2) Split vaultwarden_container_additional_networks into vaultwarden_container_additional_networks_auto and vaultwarden_container_additional_networks_custom Add a variable dedicated to the --hostname parameter of the service unit file, default value is vaultwarden_hostname Simplify labels Upgrade (1.29.2 -> 1.30.0) Upgrade (1.30.0 -> 1.30.1) Stop the container gracefully, instead of outright killing it Add vaultwarden_systemd_wanted_systemd_services_list and split required services list into multiple vars Upgrade (1.30.1 -> 1.30.2) Upgrade (1.30.2 -> 1.30.3) copied to own repository --- README.md | 12 +++ defaults/main.yml | 17 ++++ justfile | 6 ++ meta/main.yml | 15 +++ tasks/install.yml | 39 ++++++++ tasks/main.yml | 20 ++++ tasks/uninstall.yml | 25 +++++ tasks/validate_config.yml | 10 ++ templates/matterbridge.service.j2 | 37 +++++++ templates/matterbridge.toml | 158 ++++++++++++++++++++++++++++++ 10 files changed, 339 insertions(+) create mode 100644 README.md create mode 100644 defaults/main.yml create mode 100644 justfile create mode 100644 meta/main.yml create mode 100644 tasks/install.yml create mode 100644 tasks/main.yml create mode 100644 tasks/uninstall.yml create mode 100644 tasks/validate_config.yml create mode 100644 templates/matterbridge.service.j2 create mode 100644 templates/matterbridge.toml diff --git a/README.md b/README.md new file mode 100644 index 0000000..1445531 --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +# Matterbridge Ansible role + +This is an [Ansible](https://www.ansible.com/) role which installs [Matterbridge](https://github.com/dani-garcia/matterbridge) to run as a [Docker](https://www.docker.com/) container wrapped in a systemd service. + +This role _implicitly_ depends on: + +- [`com.devture.ansible.role.playbook_help`](https://github.com/devture/com.devture.ansible.role.playbook_help) +- [`com.devture.ansible.role.systemd_docker_base`](https://github.com/devture/com.devture.ansible.role.systemd_docker_base) + +Check [defaults/main.yml](defaults/main.yml) for the full list of supported options. + +For an Ansible playbook which integrates this role and makes it easier to use, see the [mash-playbook](https://github.com/mother-of-all-self-hosting/mash-playbook). diff --git a/defaults/main.yml b/defaults/main.yml new file mode 100644 index 0000000..ee87801 --- /dev/null +++ b/defaults/main.yml @@ -0,0 +1,17 @@ +--- +matterbridge_enabled: false +matterbridge_identifier: matterbridge +matterbridge_version: 1.26.0 + +matterbridge_container_registry_prefix: docker.io/ +matterbridge_container_image: "{{ matterbridge_container_registry_prefix }}42wim/matterbridge:{{ matterbridge_container_image_tag }}" +matterbridge_container_image_tag: "{{ matterbridge_version }}" +matterbridge_container_image_force_pull: "{{ matterbridge_container_image.endswith(':latest') }}" + +matterbridge_container_network: "{{ matterbridge_identifier }}" +matterbridge_uid: "{{ mash_playbook_uid }}" +matterbridge_gid: "{{ mash_playbook_gid }}" + +matterbridge_base_path: "{{ mash_playbook_base_path }}/{{ mash_playbook_service_base_directory_name_prefix }}{{ matterbridge_identifier }}" +matterbridge_config_dir_path: "{{ matterbridge_base_path }}/data" +matterbridge_toml_path: "{{ matterbridge_config_dir_path }}/matterbridge.toml" \ No newline at end of file diff --git a/justfile b/justfile new file mode 100644 index 0000000..d938c3d --- /dev/null +++ b/justfile @@ -0,0 +1,6 @@ +# show help by default +default: + @just --list --justfile {{ justfile() }} + +lint: + ansible-lint . diff --git a/meta/main.yml b/meta/main.yml new file mode 100644 index 0000000..fce213e --- /dev/null +++ b/meta/main.yml @@ -0,0 +1,15 @@ +galaxy_info: + author: mash + company: mash + role_name: matterbridge + namespace: mash + description: Matterbridge + platforms: + - name: Debian + versions: + - all + - name: Ubuntu + versions: + - all + license: GPL-3.0-or-later + min_ansible_version: '2.1' \ No newline at end of file diff --git a/tasks/install.yml b/tasks/install.yml new file mode 100644 index 0000000..877f9c3 --- /dev/null +++ b/tasks/install.yml @@ -0,0 +1,39 @@ +--- + +- name: Ensure Matterbridge paths exist + ansible.builtin.file: + path: "{{ item }}" + state: directory + mode: "0750" + owner: "{{ matterbridge_uid }}" + group: "{{ matterbridge_gid }}" + with_items: + - "{{ matterbridge_base_path }}" + - "{{ matterbridge_config_dir_path }}" + +- name: Ensure Matterbridge image is pulled + community.docker.docker_image: + name: "{{ matterbridge_container_image }}" + source: "{{ 'pull' if ansible_version.major > 2 or ansible_version.minor > 7 else omit }}" + force_source: "{{ matterbridge_container_image_force_pull if ansible_version.major > 2 or ansible_version.minor >= 8 else omit }}" + force: "{{ omit if ansible_version.major > 2 or ansible_version.minor >= 8 else matterbridge_container_image_force_pull }}" + register: result + retries: "{{ devture_playbook_help_container_retries_count }}" + delay: "{{ devture_playbook_help_container_retries_delay }}" + until: result is not failed + +- name: Ensure Matterbridge container network is created + community.general.docker_network: + name: "{{ matterbridge_container_network }}" + driver: bridge + +- name: Ensure Matterbridge systemd service installed + ansible.builtin.template: + src: "{{ role_path }}/templates/matterbridge.service.j2" + dest: "{{ devture_systemd_docker_base_systemd_path }}/{{ matterbridge_identifier }}.service" + mode: 0640 + +- name: Ensure Matterbridge config is deployed + ansible.builtin.template: + src: "{{ matterbridge_toml_src_path }}" + dest: "{{ matterbridge_toml_path }}" \ No newline at end of file diff --git a/tasks/main.yml b/tasks/main.yml new file mode 100644 index 0000000..a7fcbb9 --- /dev/null +++ b/tasks/main.yml @@ -0,0 +1,20 @@ +--- + +- block: + - when: matterbridge_enabled | bool + ansible.builtin.include_tasks: "{{ role_path }}/tasks/validate_config.yml" + + - when: matterbridge_enabled | bool + ansible.builtin.include_tasks: "{{ role_path }}/tasks/install.yml" + tags: + - setup-all + - setup-matterbridge + - install-all + - install-matterbridge + +- block: + - when: not matterbridge_enabled | bool + ansible.builtin.include_tasks: "{{ role_path }}/tasks/uninstall.yml" + tags: + - setup-all + - setup-matterbridge diff --git a/tasks/uninstall.yml b/tasks/uninstall.yml new file mode 100644 index 0000000..c6a4780 --- /dev/null +++ b/tasks/uninstall.yml @@ -0,0 +1,25 @@ +--- + +- name: Check existence of Matterbridge systemd service + ansible.builtin.stat: + path: "{{ devture_systemd_docker_base_systemd_path }}/{{ matterbridge_identifier }}.service" + register: matterbridge_service_stat + +- when: matterbridge_service_stat.stat.exists | bool + block: + - name: Ensure Matterbridge systemd service is stopped + ansible.builtin.service: + name: "{{ matterbridge_identifier }}" + state: stopped + enabled: false + daemon_reload: true + + - name: Ensure Matterbridge systemd service does not exists + ansible.builtin.file: + path: "{{ devture_systemd_docker_base_systemd_path }}/{{ matterbridge_identifier }}.service" + state: absent + + - name: Ensure Matterbridge path doesn't exist + ansible.builtin.file: + path: "{{ matterbridge_base_path }}" + state: absent diff --git a/tasks/validate_config.yml b/tasks/validate_config.yml new file mode 100644 index 0000000..6a58779 --- /dev/null +++ b/tasks/validate_config.yml @@ -0,0 +1,10 @@ +--- + +- name: Fail if required Mattermost settings not defined + ansible.builtin.fail: + msg: > + You need to define a required configuration setting (`{{ item }}`). + when: "vars[item] == ''" + with_items: + - matterbridge_toml_src_path + diff --git a/templates/matterbridge.service.j2 b/templates/matterbridge.service.j2 new file mode 100644 index 0000000..99e7320 --- /dev/null +++ b/templates/matterbridge.service.j2 @@ -0,0 +1,37 @@ +[Unit] +Description=Matterbridge ({{ matterbridge_identifier }}) +DefaultDependencies=no + +[Service] +Type=simple +Environment="HOME={{ devture_systemd_docker_base_systemd_unit_home_path }}" +ExecStartPre=-{{ devture_systemd_docker_base_host_command_sh }} -c '{{ devture_systemd_docker_base_host_command_docker }} kill {{ matterbridge_identifier }} 2>/dev/null' +ExecStartPre=-{{ devture_systemd_docker_base_host_command_sh }} -c '{{ devture_systemd_docker_base_host_command_docker }} rm {{ matterbridge_identifier }} 2>/dev/null' + +{# + The `--health-interval` health check parameter was changed because by default: + - health checks start immediately.. and they always fail, because the HTTP server takes a bit of time to start + - the recheck interval is too long (60s) and the service is considered `starting` + - when a service is not `healthy`, Traefik does not reverse-proxy to it -- leading to 1 minute downtime every single time this restarts +#} +ExecStartPre={{ devture_systemd_docker_base_host_command_docker }} create \ + --rm \ + --name={{ matterbridge_identifier }} \ + --log-driver=none \ + --network={{ matterbridge_container_network }} \ + --user={{ matterbridge_uid }}:{{ matterbridge_gid }} \ + --cap-drop=ALL \ + --health-interval=10s \ + --mount type=bind,src={{ matterbridge_toml_path }},dst=/etc/matterbridge/matterbridge.toml \ + {{ matterbridge_container_image }} + +ExecStart={{ devture_systemd_docker_base_host_command_docker }} start --attach {{ matterbridge_identifier }} + +ExecStop=-{{ devture_systemd_docker_base_host_command_sh }} -c '{{ devture_systemd_docker_base_host_command_docker }} stop {{ matterbridge_identifier }} 2>/dev/null' +ExecStop=-{{ devture_systemd_docker_base_host_command_sh }} -c '{{ devture_systemd_docker_base_host_command_docker }} rm {{ matterbridge_identifier }} 2>/dev/null' +Restart=always +RestartSec=30 +SyslogIdentifier={{ matterbridge_identifier }} + +[Install] +WantedBy=multi-user.target diff --git a/templates/matterbridge.toml b/templates/matterbridge.toml new file mode 100644 index 0000000..0d3afd2 --- /dev/null +++ b/templates/matterbridge.toml @@ -0,0 +1,158 @@ +################################################################### +#IRC section +################################################################### + +[irc] +[irc.{{ default_irc_network_name }}] +Server="{{ default_irc_network_server }}" +UseTLS=true +SkipTLSVerify=false +UseSASL=false + +Nick="{{ default_irc_bot_nick }}" +#UseSASL=true +#NickServNick="" +#NickServPassword="" + +## RELOADABLE SETTINGS +## Settings below can be reloaded by editing the file + +#Split messages on MessageLength instead of showing the +#WARNING: this could lead to flooding +#OPTIONAL (default false) +MessageSplit=true + +#ColorNicks will show each nickname in a different color. +#Only works in IRC right now. +ColorNicks=true + +#Nicks you want to ignore. +#Messages from those users will not be sent to other bridges. +#OPTIONAL +IgnoreNicks="{{ default_irc_ignore_nicks }}" + +#RemoteNickFormat defines how remote users appear on this bridge +RemoteNickFormat="<{NOPINGNICK}> " + +#Enable to show users joins/parts from other bridges +#Currently works for messages from the following bridges: irc, mattermost, slack +#OPTIONAL (default false) +ShowJoinPart=true + +#Enable to show topic changes from other bridges +#Only works hiding/show topic changes from slack bridge for now +#OPTIONAL (default false) +ShowTopicChange=true + + +################################################################### +#slack section +################################################################### +[slack] +[slack.{{ default_slack_team_name }}] +Token="{{ default_slack_api_token }}" + +#Icon that will be showed in slack +#The string "{NICK}" (case sensitive) will be replaced by the actual nick / username. +#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge +#The string "{LABEL}" (case sensitive) will be replaced by label= field of the sending bridge +#The string "{PROTOCOL}" (case sensitive) will be replaced by the protocol used by the bridge +#OPTIONAL +IconURL="https://robohash.org/{NICK}.png?size=48x48" + +## RELOADABLE SETTINGS +## Settings below can be reloaded by editing the file + +#Message to be appended to every edited message +#OPTIONAL (default empty) +EditSuffix=" (edited)" + +#Whether to prefix messages from other bridges to mattermost with RemoteNickFormat +#Useful if username overrides for incoming webhooks isn't enabled on the +#slack server. If you set PrefixMessagesWithNick to true, each message +#from bridge to Slack will by default be prefixed by "bridge-" + nick. You can, +#however, modify how the messages appear, by setting (and modifying) RemoteNickFormat +#OPTIONAL (default false) +PrefixMessagesWithNick=false + +#Nicks you want to ignore. +#Messages from those users will not be sent to other bridges. +#OPTIONAL +IgnoreNicks="{{ default_slack_ignore_nicks }}" + +#Opportunistically preserve threaded replies between Slack channels. +#This only works if the parent message is still in the cache. +#Cache is flushed between restarts. +#OPTIONAL (default false) +PreserveThreading=true + + +################################################################### +#General configuration +################################################################### +# Settings here are defaults that each protocol can override +[general] + +## RELOADABLE SETTINGS +## Settings below can be reloaded by editing the file + +#RemoteNickFormat defines how remote users appear on this bridge +#The string "{NICK}" (case sensitive) will be replaced by the actual nick / username. +#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge +#The string "{LABEL}" (case sensitive) will be replaced by label= field of the sending bridge +#The string "{PROTOCOL}" (case sensitive) will be replaced by the protocol used by the bridge +#The string "{GATEWAY}" (case sensitive) will be replaced by the origin gateway name that is replicating the message. +#The string "{CHANNEL}" (case sensitive) will be replaced by the origin channel name used by the bridge +#OPTIONAL (default empty) +RemoteNickFormat="[{PROTOCOL}] <{NICK}> " + +#MediaServerUpload (or MediaDownloadPath) and MediaServerDownload are used for uploading +#images/files/video to a remote "mediaserver" (a webserver like caddy for example). +#When configured images/files uploaded on bridges like mattermost, slack, telegram will be +#downloaded and uploaded again to MediaServerUpload URL +#MediaDownloadPath is the filesystem path where the media file will be placed, instead of uploaded, +#for if Matterbridge has write access to the directory your webserver is serving. +#It is an alternative to MediaServerUpload. +#The MediaServerDownload will be used so that bridges without native uploading support: +#gitter, irc and xmpp will be shown links to the files on MediaServerDownload +# +#More information https://github.com/42wim/matterbridge/wiki/Mediaserver-setup-%5Badvanced%5D +#OPTIONAL (default empty) +#MediaServerUpload="https://user:pass@yourserver.com/upload" +#OPTIONAL (default empty) +#MediaDownloadPath="/srv/http/yourserver.com/public/download" +#OPTIONAL (default empty) +#MediaServerDownload="https://youserver.com/download" + +#MediaDownloadSize is the maximum size of attachments, videos, images +#matterbridge will download and upload this file to bridges that also support uploading files. +#eg downloading from slack to upload it to mattermost +# +#It will only download from bridges that don't have public links available, which are for the moment +#slack, telegram, matrix and mattermost +# +#OPTIONAL (default 1000000 (1 megabyte)) +#MediaDownloadSize=1000000 + +#MediaDownloadBlacklist allows you to blacklist specific files from being downloaded. +#Filenames matching these regexp will not be download/uploaded to the mediaserver +#You can use regex for this, see https://regex-golang.appspot.com/assets/html/index.html for more regex info +#OPTIONAL (default empty) +#MediaDownloadBlacklist=[".html$",".htm$"] + + +################################################################### +#Gateway configuration +################################################################### + +[[gateway]] +name="gateway_mycommunity" +enable=true + + [[gateway.inout]] + account="irc.{{ default_irc_network_name }}" + channel="{{ matterbridge_config.my_community.irc.channel }}" + + [[gateway.inout]] + account="slack.{{ default_slack_team_name }}" + channel="{{ matterbridge_config.my_community.slack.channel }}" \ No newline at end of file