mirror of
https://github.com/spantaleev/matrix-docker-ansible-deploy.git
synced 2026-07-12 18:04:24 +03:00
Add add-inventory-host command for bootstrapping the inventory
Running `just add-inventory-host example.com 1.2.3.4` (or `make add-inventory-host domain=example.com ip=1.2.3.4`) adds a new host to the inventory, creating inventory/hosts and inventory/host_vars/matrix.DOMAIN/vars.yml from the example files, with strong secrets generated automatically. Existing configuration is never overwritten. The command refuses to run if the host is already in the inventory, so it can also be used for adding more hosts later. Based on the idea proposed in https://github.com/spantaleev/matrix-docker-ansible-deploy/pull/4682 by @Ser5 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,11 +2,14 @@
|
||||
#
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
.PHONY: roles lint
|
||||
.PHONY: roles lint add-inventory-host
|
||||
|
||||
help: ## Show this help.
|
||||
@grep -F -h "##" $(MAKEFILE_LIST) | grep -v grep | sed -e 's/\\$$//' | sed -e 's/##//'
|
||||
|
||||
add-inventory-host: ## Adds a new host to the inventory, creating the inventory files if necessary (e.g. `make add-inventory-host domain=example.com ip=1.2.3.4`)
|
||||
@./bin/add-inventory-host.sh "$(domain)" "$(ip)"
|
||||
|
||||
roles: ## Pull roles
|
||||
rm -rf roles/galaxy
|
||||
ansible-galaxy install -r requirements.yml -p roles/galaxy/ --force
|
||||
|
||||
Executable
+120
@@ -0,0 +1,120 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# SPDX-FileCopyrightText: 2026 MDAD project contributors
|
||||
# SPDX-FileCopyrightText: 2026 Slavi Pantaleev
|
||||
#
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# Adds a new host to the inventory, based on the example files in `examples/`:
|
||||
# - creates `inventory/hosts` (or adds the host to it, if it already exists)
|
||||
# - creates `inventory/host_vars/matrix.DOMAIN/vars.yml` with strong secrets generated automatically
|
||||
#
|
||||
# Existing configuration for the same host is never overwritten - the script refuses to run instead.
|
||||
#
|
||||
# Usage: bin/add-inventory-host.sh <base-domain> <server-address>
|
||||
#
|
||||
# - <base-domain> is the base domain (`example.com`), not the Matrix server hostname (`matrix.example.com`)
|
||||
# - <server-address> is the server's external IP address or domain name
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
base_path="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
|
||||
if [ $# -ne 2 ]; then
|
||||
echo "Usage: $0 <base-domain> <server-address>" >&2
|
||||
echo "Example: $0 example.com 1.2.3.4" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
domain="$1"
|
||||
server_address="$2"
|
||||
|
||||
if ! printf '%s' "${domain}" | grep -Eq '^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)+$'; then
|
||||
echo "Error: '${domain}' does not look like a valid domain name" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! printf '%s' "${server_address}" | grep -Eq '^[A-Za-z0-9.:_-]+$'; then
|
||||
echo "Error: '${server_address}' does not look like a valid server address (IP address or domain name)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case "${domain}" in
|
||||
matrix.*)
|
||||
echo "Warning: you likely need to pass your base domain (example.com), not the Matrix server hostname (matrix.example.com)." >&2
|
||||
echo "Proceeding anyway. Your Matrix server hostname will be: matrix.${domain}" >&2
|
||||
;;
|
||||
esac
|
||||
|
||||
matrix_hostname="matrix.${domain}"
|
||||
hosts_file="${base_path}/inventory/hosts"
|
||||
vars_dir="${base_path}/inventory/host_vars/${matrix_hostname}"
|
||||
vars_file="${vars_dir}/vars.yml"
|
||||
hosts_entry="${matrix_hostname} ansible_host=${server_address} ansible_ssh_user=root"
|
||||
|
||||
if [ -e "${vars_dir}" ]; then
|
||||
echo "Error: ${vars_dir} already exists. Refusing to overwrite it." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -f "${hosts_file}" ]; then
|
||||
if ! grep -q '^\[matrix_servers\]' "${hosts_file}"; then
|
||||
echo "Error: ${hosts_file} exists, but does not contain a [matrix_servers] section." >&2
|
||||
echo "Unrecognized inventory format. Add the host to it manually:" >&2
|
||||
echo "${hosts_entry}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
matrix_hostname_pattern="$(printf '%s' "${matrix_hostname}" | sed 's|\.|\\.|g')"
|
||||
if grep -Eq "^${matrix_hostname_pattern}([[:space:]]|$)" "${hosts_file}"; then
|
||||
echo "Error: ${hosts_file} already contains an entry for ${matrix_hostname}. Refusing to modify it." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
generate_secret() {
|
||||
if command -v pwgen >/dev/null 2>&1; then
|
||||
pwgen -s 64 1
|
||||
elif command -v openssl >/dev/null 2>&1; then
|
||||
openssl rand -base64 192 | LC_ALL=C tr -dc 'A-Za-z0-9' | head -c 64
|
||||
else
|
||||
head -c 4096 /dev/urandom | LC_ALL=C tr -dc 'A-Za-z0-9' | head -c 64
|
||||
fi
|
||||
}
|
||||
|
||||
generic_secret_key="$(generate_secret)"
|
||||
postgres_password="$(generate_secret)"
|
||||
|
||||
for secret in "${generic_secret_key}" "${postgres_password}"; do
|
||||
if [ "${#secret}" -lt 64 ]; then
|
||||
echo "Error: failed to generate a secret" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
mkdir -p "${vars_dir}"
|
||||
|
||||
sed \
|
||||
-e "s|^matrix_domain:.*|matrix_domain: ${domain}|" \
|
||||
-e "s|^matrix_homeserver_generic_secret_key:.*|matrix_homeserver_generic_secret_key: '${generic_secret_key}'|" \
|
||||
-e "s|^postgres_connection_password:.*|postgres_connection_password: '${postgres_password}'|" \
|
||||
"${base_path}/examples/vars.yml" > "${vars_file}"
|
||||
|
||||
if [ -f "${hosts_file}" ]; then
|
||||
# Insert the new host right after the [matrix_servers] section header.
|
||||
hosts_file_tmp="$(mktemp "${hosts_file}.XXXXXX")"
|
||||
awk -v entry="${hosts_entry}" '{print} $0 ~ /^\[matrix_servers\]/ && !done {print entry; done=1}' \
|
||||
"${hosts_file}" > "${hosts_file_tmp}"
|
||||
mv "${hosts_file_tmp}" "${hosts_file}"
|
||||
else
|
||||
sed \
|
||||
-e "s|^matrix\.example\.com .*|${hosts_entry}|" \
|
||||
"${base_path}/examples/hosts" > "${hosts_file}"
|
||||
fi
|
||||
|
||||
echo "Added host ${matrix_hostname} to the inventory:"
|
||||
echo "- ${hosts_file}"
|
||||
echo "- ${vars_file}"
|
||||
echo ""
|
||||
echo "Secrets were generated automatically for matrix_homeserver_generic_secret_key and postgres_connection_password."
|
||||
echo "Review and adjust these files before installing."
|
||||
+17
-1
@@ -89,7 +89,23 @@ To install Matrix services with this playbook, you would at least need 2 configu
|
||||
|
||||
For your convenience, we have prepared example files of them ([`vars.yml`](../examples/vars.yml) and [`hosts`](../examples/hosts)).
|
||||
|
||||
To start quickly based on these example files, go into the `matrix-docker-ansible-deploy` directory and follow the instructions below:
|
||||
To start quickly based on these example files, go into the `matrix-docker-ansible-deploy` directory and initialize your configuration, either automatically or manually.
|
||||
|
||||
To initialize it automatically (with the base domain and server address pre-filled and secrets generated for you), run:
|
||||
|
||||
- either: `just add-inventory-host example.com 1.2.3.4` (if you have the [`just`](just.md) tool)
|
||||
- or: `make add-inventory-host domain=example.com ip=1.2.3.4` (if you have the `make` program)
|
||||
|
||||
… where `example.com` is your "base domain" (not `matrix.example.com`) and `1.2.3.4` is your server's external IP address (or domain name).
|
||||
|
||||
Given a base domain of `example.com`, this creates:
|
||||
|
||||
- an entry for `matrix.example.com` (the Matrix server's default hostname: `matrix.` + your base domain) in the inventory hosts file (`inventory/hosts`)
|
||||
- a configuration file (`inventory/host_vars/matrix.example.com/vars.yml`) containing `matrix_domain: example.com` and automatically generated secrets
|
||||
|
||||
Afterward, edit these 2 files to adjust them further, as necessary. Existing configuration is never overwritten (the command refuses to run if the host is already in your inventory), so it can also be used for adding more hosts later.
|
||||
|
||||
To initialize it manually, follow the instructions below:
|
||||
|
||||
1. Create a directory to hold your configuration: `mkdir -p inventory/host_vars/matrix.example.com` where `example.com` is your "base domain"
|
||||
2. Copy the sample configuration file: `cp examples/vars.yml inventory/host_vars/matrix.example.com/vars.yml`
|
||||
|
||||
@@ -13,6 +13,10 @@ prek_home := env("PREK_HOME", justfile_directory() / "var/prek")
|
||||
default:
|
||||
@{{ just_executable() }} --list --justfile "{{ justfile() }}"
|
||||
|
||||
# Adds a new host to the inventory, creating the inventory files if necessary (e.g. `just add-inventory-host example.com 1.2.3.4`)
|
||||
add-inventory-host domain server_address:
|
||||
@{{ justfile_directory() }}/bin/add-inventory-host.sh {{ quote(domain) }} {{ quote(server_address) }}
|
||||
|
||||
# Pulls external Ansible roles
|
||||
roles:
|
||||
#!/usr/bin/env sh
|
||||
|
||||
Reference in New Issue
Block a user