From 36f1f0112029d22466f2adcd26b4976339b724aa Mon Sep 17 00:00:00 2001 From: Julien Riou Date: Mon, 23 Mar 2026 10:37:28 +0100 Subject: [PATCH] Initial commit Signed-off-by: Julien Riou --- .forgejo/workflows/ansible-ci.yml | 38 +++ .gitignore | 2 + LICENSE | 9 + README.md | 3 + galaxy.yml | 29 +++ roles/certbot/README.md | 61 +++++ roles/certbot/defaults/main.yml | 10 + roles/certbot/meta/argument_specs.yml | 25 ++ roles/certbot/molecule/default/converge.yml | 9 + roles/certbot/molecule/default/create.yml | 18 ++ roles/certbot/molecule/default/destroy.yml | 11 + .../molecule/default/inventory/hosts.yml | 12 + roles/certbot/molecule/default/molecule.yml | 24 ++ .../certbot/molecule/default/requirements.yml | 3 + roles/certbot/tasks/main.yml | 13 + roles/coller/README.md | 159 ++++++++++++ roles/coller/defaults/main.yml | 51 ++++ roles/coller/handlers/main.yml | 4 + roles/coller/meta/argument_specs.yml | 52 ++++ roles/coller/meta/main.yml | 3 + roles/coller/tasks/main.yml | 55 ++++ roles/coller/tasks/manage-iptables.yml | 16 ++ roles/coller/templates/db.env.j2 | 6 + roles/coller/templates/docker-compose.yml.j2 | 32 +++ roles/firefly/README.md | 234 +++++++++++++++++ roles/firefly/defaults/main.yml | 66 +++++ roles/firefly/handlers/main.yml | 4 + roles/firefly/meta/argument_specs.yml | 76 ++++++ roles/firefly/meta/main.yml | 3 + roles/firefly/tasks/main.yml | 47 ++++ roles/firefly/templates/app.env.j2 | 132 ++++++++++ roles/firefly/templates/db.env.j2 | 5 + roles/firefly/templates/docker-compose.yml.j2 | 40 +++ roles/forgejo/README.md | 239 ++++++++++++++++++ roles/forgejo/defaults/main.yml | 91 +++++++ roles/forgejo/handlers/main.yml | 4 + roles/forgejo/meta/argument_specs.yml | 84 ++++++ roles/forgejo/meta/main.yml | 3 + roles/forgejo/tasks/main.yml | 72 ++++++ roles/forgejo/templates/db.env.j2 | 6 + roles/forgejo/templates/docker-compose.yml.j2 | 35 +++ roles/forgejo/templates/server.env.j2 | 19 ++ roles/forgejo_runners/README.md | 146 +++++++++++ roles/forgejo_runners/defaults/main.yml | 39 +++ roles/forgejo_runners/handlers/main.yml | 13 + roles/forgejo_runners/meta/argument_specs.yml | 40 +++ roles/forgejo_runners/meta/main.yml | 3 + roles/forgejo_runners/tasks/main.yml | 33 +++ .../forgejo_runners/tasks/register-runner.yml | 39 +++ roles/forgejo_runners/templates/config.yml.j2 | 44 ++++ .../templates/docker-compose.yml.j2 | 27 ++ roles/galene/README.md | 213 ++++++++++++++++ roles/galene/defaults/main.yml | 95 +++++++ roles/galene/handlers/main.yml | 9 + roles/galene/meta/argument_specs.yml | 85 +++++++ roles/galene/meta/main.yml | 3 + roles/galene/molecule/default/converge.yml | 5 + roles/galene/molecule/default/create.yml | 18 ++ roles/galene/molecule/default/destroy.yml | 11 + .../molecule/default/inventory/hosts.yml | 12 + roles/galene/molecule/default/molecule.yml | 26 ++ .../galene/molecule/default/requirements.yml | 3 + roles/galene/molecule/default/verify.yml | 8 + roles/galene/tasks/main.yml | 117 +++++++++ roles/galene/templates/galene.service.j2 | 19 ++ roles/golang/README.md | 34 +++ roles/golang/defaults/main.yml | 8 + roles/golang/meta/argument_specs.yml | 13 + roles/golang/molecule/default/converge.yml | 7 + roles/golang/molecule/default/create.yml | 18 ++ roles/golang/molecule/default/destroy.yml | 11 + .../molecule/default/inventory/hosts.yml | 12 + roles/golang/molecule/default/molecule.yml | 26 ++ .../golang/molecule/default/requirements.yml | 3 + roles/golang/molecule/default/verify.yml | 15 ++ roles/golang/tasks/main.yml | 7 + roles/navidrome/.gitignore | 1 + roles/navidrome/README.md | 205 +++++++++++++++ roles/navidrome/defaults/main.yml | 84 ++++++ roles/navidrome/handlers/main.yml | 14 + roles/navidrome/meta/argument_specs.yml | 78 ++++++ roles/navidrome/tasks/main.yml | 62 +++++ roles/navidrome/templates/navidrome.toml.j2 | 10 + roles/navidrome/templates/override.conf.j2 | 5 + test-requirements.txt | 2 + test-requirements.yml | 3 + 86 files changed, 3431 insertions(+) create mode 100644 .forgejo/workflows/ansible-ci.yml create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 galaxy.yml create mode 100644 roles/certbot/README.md create mode 100644 roles/certbot/defaults/main.yml create mode 100644 roles/certbot/meta/argument_specs.yml create mode 100644 roles/certbot/molecule/default/converge.yml create mode 100644 roles/certbot/molecule/default/create.yml create mode 100644 roles/certbot/molecule/default/destroy.yml create mode 100644 roles/certbot/molecule/default/inventory/hosts.yml create mode 100644 roles/certbot/molecule/default/molecule.yml create mode 100644 roles/certbot/molecule/default/requirements.yml create mode 100644 roles/certbot/tasks/main.yml create mode 100644 roles/coller/README.md create mode 100644 roles/coller/defaults/main.yml create mode 100644 roles/coller/handlers/main.yml create mode 100644 roles/coller/meta/argument_specs.yml create mode 100644 roles/coller/meta/main.yml create mode 100644 roles/coller/tasks/main.yml create mode 100644 roles/coller/tasks/manage-iptables.yml create mode 100644 roles/coller/templates/db.env.j2 create mode 100644 roles/coller/templates/docker-compose.yml.j2 create mode 100644 roles/firefly/README.md create mode 100644 roles/firefly/defaults/main.yml create mode 100644 roles/firefly/handlers/main.yml create mode 100644 roles/firefly/meta/argument_specs.yml create mode 100644 roles/firefly/meta/main.yml create mode 100644 roles/firefly/tasks/main.yml create mode 100644 roles/firefly/templates/app.env.j2 create mode 100644 roles/firefly/templates/db.env.j2 create mode 100644 roles/firefly/templates/docker-compose.yml.j2 create mode 100644 roles/forgejo/README.md create mode 100644 roles/forgejo/defaults/main.yml create mode 100644 roles/forgejo/handlers/main.yml create mode 100644 roles/forgejo/meta/argument_specs.yml create mode 100644 roles/forgejo/meta/main.yml create mode 100644 roles/forgejo/tasks/main.yml create mode 100644 roles/forgejo/templates/db.env.j2 create mode 100644 roles/forgejo/templates/docker-compose.yml.j2 create mode 100644 roles/forgejo/templates/server.env.j2 create mode 100644 roles/forgejo_runners/README.md create mode 100644 roles/forgejo_runners/defaults/main.yml create mode 100644 roles/forgejo_runners/handlers/main.yml create mode 100644 roles/forgejo_runners/meta/argument_specs.yml create mode 100644 roles/forgejo_runners/meta/main.yml create mode 100644 roles/forgejo_runners/tasks/main.yml create mode 100644 roles/forgejo_runners/tasks/register-runner.yml create mode 100644 roles/forgejo_runners/templates/config.yml.j2 create mode 100644 roles/forgejo_runners/templates/docker-compose.yml.j2 create mode 100644 roles/galene/README.md create mode 100644 roles/galene/defaults/main.yml create mode 100644 roles/galene/handlers/main.yml create mode 100644 roles/galene/meta/argument_specs.yml create mode 100644 roles/galene/meta/main.yml create mode 100644 roles/galene/molecule/default/converge.yml create mode 100644 roles/galene/molecule/default/create.yml create mode 100644 roles/galene/molecule/default/destroy.yml create mode 100644 roles/galene/molecule/default/inventory/hosts.yml create mode 100644 roles/galene/molecule/default/molecule.yml create mode 100644 roles/galene/molecule/default/requirements.yml create mode 100644 roles/galene/molecule/default/verify.yml create mode 100644 roles/galene/tasks/main.yml create mode 100644 roles/galene/templates/galene.service.j2 create mode 100644 roles/golang/README.md create mode 100644 roles/golang/defaults/main.yml create mode 100644 roles/golang/meta/argument_specs.yml create mode 100644 roles/golang/molecule/default/converge.yml create mode 100644 roles/golang/molecule/default/create.yml create mode 100644 roles/golang/molecule/default/destroy.yml create mode 100644 roles/golang/molecule/default/inventory/hosts.yml create mode 100644 roles/golang/molecule/default/molecule.yml create mode 100644 roles/golang/molecule/default/requirements.yml create mode 100644 roles/golang/molecule/default/verify.yml create mode 100644 roles/golang/tasks/main.yml create mode 100644 roles/navidrome/.gitignore create mode 100644 roles/navidrome/README.md create mode 100644 roles/navidrome/defaults/main.yml create mode 100644 roles/navidrome/handlers/main.yml create mode 100644 roles/navidrome/meta/argument_specs.yml create mode 100644 roles/navidrome/tasks/main.yml create mode 100644 roles/navidrome/templates/navidrome.toml.j2 create mode 100644 roles/navidrome/templates/override.conf.j2 create mode 100644 test-requirements.txt create mode 100644 test-requirements.yml diff --git a/.forgejo/workflows/ansible-ci.yml b/.forgejo/workflows/ansible-ci.yml new file mode 100644 index 0000000..af2bd69 --- /dev/null +++ b/.forgejo/workflows/ansible-ci.yml @@ -0,0 +1,38 @@ +--- +on: + - push + +jobs: + ansible-docsmith: + runs-on: node-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install ansible-docsmith + run: | + apt-get update + apt-get install -y python3-pip + pip install ansible-docsmith --break-system-packages + + - name: Run ansible-docsmith + run: | + for role_dir in $(ls --color=none roles); do + ansible-docsmith generate "roles/${role_dir}" + done + + - name: Verify changes + run: | + set -e + git diff > diff.txt + CHANGES=$(wc -l diff.txt | awk '{ print $1 }') + echo "Number of changes: ${CHANGES}" + if [ ${CHANGES} -gt 0 ] ; then + echo "" + cat diff.txt + echo "" + echo "Fix with the following command:" + echo "" + echo "run ansible-docsmith generate ${role_dir}" + exit 1 + fi diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f646311 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +venv +TODO.txt diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2bad0ce --- /dev/null +++ b/LICENSE @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) 2026 jriou + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..9dc8a84 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# Ansible + +My Ansible collection. diff --git a/galaxy.yml b/galaxy.yml new file mode 100644 index 0000000..497d0fe --- /dev/null +++ b/galaxy.yml @@ -0,0 +1,29 @@ +--- +namespace: jriou +name: general +version: 1.0.0 +readme: README.md +authors: + - "Julien Riou (https://git.riou.xyz/jriou)" +description: "My Ansible Collection" +license_file: LICENSE +tags: + - infrastructure + - certbot + - coller + - firefly + - forgejo + - forgejo_runners + - galene + - golang + - navidrome +repository: "https://git.riou.xyz/jriou/ansible" +issues: "https://git.riou.xyz/jriou/ansible/issues" +build_ignore: + - .github + - .gitignore + - changelogs + - roles/*/molecule + - '*.tar.gz' + - test-requirements.txt + - test-requirements.yml diff --git a/roles/certbot/README.md b/roles/certbot/README.md new file mode 100644 index 0000000..f354e3c --- /dev/null +++ b/roles/certbot/README.md @@ -0,0 +1,61 @@ +# Ansible Role Certbot + +## Table of content + + +* [Role variables](#variables) + * [`certbot_email`](#variable-certbot_email) + * [`certbot_domain`](#variable-certbot_domain) + * [`certbot_molecule`](#variable-certbot_molecule) + + + + +## Role variables + +The following variables can be configured for this role: + +| Variable | Type | Required | Default | Description (abstract) | +|----------|------|----------|---------|------------------------| +| `certbot_email` | `str` | Yes | N/A | E-mail to register the certificate. | +| `certbot_domain` | `str` | Yes | N/A | Domain name to register the certificate. | +| `certbot_molecule` | `bool` | No | `false` | Run the role with Ansible Molecule.

Disable cert generation in the CI. | + +### `certbot_email` + +[*⇑ Back to ToC ⇑*](#toc) + +E-mail to register the certificate. + +- **Type**: `str` +- **Required**: Yes + + + +### `certbot_domain` + +[*⇑ Back to ToC ⇑*](#toc) + +Domain name to register the certificate. + +- **Type**: `str` +- **Required**: Yes + + + +### `certbot_molecule` + +[*⇑ Back to ToC ⇑*](#toc) + +Run the role with Ansible Molecule. + +Disable cert generation in the CI. + +- **Type**: `bool` +- **Required**: No +- **Default**: `false` + + + + + diff --git a/roles/certbot/defaults/main.yml b/roles/certbot/defaults/main.yml new file mode 100644 index 0000000..e795850 --- /dev/null +++ b/roles/certbot/defaults/main.yml @@ -0,0 +1,10 @@ +--- + +# Run the role with Ansible Molecule. +# +# Disable cert generation in the CI. +# +# - Type: bool +# - Required: No +# - Default: false +certbot_molecule: false diff --git a/roles/certbot/meta/argument_specs.yml b/roles/certbot/meta/argument_specs.yml new file mode 100644 index 0000000..17df03e --- /dev/null +++ b/roles/certbot/meta/argument_specs.yml @@ -0,0 +1,25 @@ +--- +argument_specs: + main: + short_description: Install and configure a certbot + description: + - Install and configure a [certbot](https://certbot.eff.org/). + author: + - jriou + options: + certbot_email: + description: + - E-mail to register the certificate. + required: true + + certbot_domain: + description: + - Domain name to register the certificate. + required: true + + certbot_molecule: + description: + - Run the role with Ansible Molecule. + - Disable cert generation in the CI. + type: bool + default: false diff --git a/roles/certbot/molecule/default/converge.yml b/roles/certbot/molecule/default/converge.yml new file mode 100644 index 0000000..8f529c8 --- /dev/null +++ b/roles/certbot/molecule/default/converge.yml @@ -0,0 +1,9 @@ +--- +- name: Converge + hosts: molecule + roles: + - certbot + vars: + certbot_domain: test.org + certbot_email: test@test.org + certbot_molecule: true diff --git a/roles/certbot/molecule/default/create.yml b/roles/certbot/molecule/default/create.yml new file mode 100644 index 0000000..6049019 --- /dev/null +++ b/roles/certbot/molecule/default/create.yml @@ -0,0 +1,18 @@ +--- +- name: Create containers + hosts: localhost + gather_facts: false + tasks: + - name: Create containers + containers.podman.podman_container: + hostname: "{{ item }}" + name: "{{ item }}" + image: "{{ hostvars[item]['container_image'] }}" + state: started + loop: "{{ groups['molecule'] }}" + + - name: Wait for containers to be ready + ansible.builtin.wait_for_connection: + timeout: 300 + delegate_to: "{{ item }}" + loop: "{{ groups['molecule'] }}" diff --git a/roles/certbot/molecule/default/destroy.yml b/roles/certbot/molecule/default/destroy.yml new file mode 100644 index 0000000..b0596be --- /dev/null +++ b/roles/certbot/molecule/default/destroy.yml @@ -0,0 +1,11 @@ +--- +- name: Destroy container instances + hosts: localhost + gather_facts: false + tasks: + - name: Remove containers + containers.podman.podman_container: + name: "{{ item }}" + state: absent + loop: "{{ groups['molecule'] }}" + failed_when: false diff --git a/roles/certbot/molecule/default/inventory/hosts.yml b/roles/certbot/molecule/default/inventory/hosts.yml new file mode 100644 index 0000000..f107edb --- /dev/null +++ b/roles/certbot/molecule/default/inventory/hosts.yml @@ -0,0 +1,12 @@ +--- +molecule: + hosts: + debian11: + ansible_connection: containers.podman.podman + container_image: docker.io/geerlingguy/docker-debian11-ansible:latest + debian12: + ansible_connection: containers.podman.podman + container_image: docker.io/geerlingguy/docker-debian12-ansible:latest + debian13: + ansible_connection: containers.podman.podman + container_image: docker.io/geerlingguy/docker-debian13-ansible:latest diff --git a/roles/certbot/molecule/default/molecule.yml b/roles/certbot/molecule/default/molecule.yml new file mode 100644 index 0000000..b4d7fb1 --- /dev/null +++ b/roles/certbot/molecule/default/molecule.yml @@ -0,0 +1,24 @@ +--- +ansible: + executor: + args: + ansible_playbook: + - --inventory=inventory/ + env: + ANSIBLE_ROLES_PATH: ../../../../roles + playbooks: + create: create.yml + destroy: destroy.yml + converge: converge.yml + +dependency: + name: galaxy + options: + requirements-file: ${MOLECULE_SCENARIO_DIRECTORY}/requirements.yml + +scenario: + test_sequence: + - create + - converge + - idempotence + - destroy diff --git a/roles/certbot/molecule/default/requirements.yml b/roles/certbot/molecule/default/requirements.yml new file mode 100644 index 0000000..25a97a4 --- /dev/null +++ b/roles/certbot/molecule/default/requirements.yml @@ -0,0 +1,3 @@ +--- +collections: + - name: containers.podman diff --git a/roles/certbot/tasks/main.yml b/roles/certbot/tasks/main.yml new file mode 100644 index 0000000..bfea560 --- /dev/null +++ b/roles/certbot/tasks/main.yml @@ -0,0 +1,13 @@ +--- +- name: Install packages + ansible.builtin.apt: + name: certbot + update_cache: true + +- name: Request certificate + ansible.builtin.command: + cmd: >- + certbot certonly --standalone -n --agree-tos + --email {{ certbot_email }} -d {{ certbot_domain }} + creates: /etc/letsencrypt/live/{{ certbot_domain }}/fullchain.pem + when: not certbot_molecule diff --git a/roles/coller/README.md b/roles/coller/README.md new file mode 100644 index 0000000..c1da5ea --- /dev/null +++ b/roles/coller/README.md @@ -0,0 +1,159 @@ +# Ansible Role Coller + +Ansible role to manage a [coller](https://git.riou.xyz/jriou/coller) instance. + +## Configuration + +See [Variable +precedence](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_variables.html#ansible-variable-precedence) +to find where you should put your own variables. + +Then define at least `coller_db_password` with a strong and secure password, +encrypted using +[ansible-vault](https://docs.ansible.com/ansible/latest/cli/ansible-vault.html). + +## Table of content + + +* [Role variables](#variables) + * [`coller_version`](#variable-coller_version) + * [`coller_config_dir`](#variable-coller_config_dir) + * [`coller_port`](#variable-coller_port) + * [`coller_manage_iptables`](#variable-coller_manage_iptables) + * [`coller_allowed_sources`](#variable-coller_allowed_sources) + * [`coller_db_name`](#variable-coller_db_name) + * [`coller_db_user`](#variable-coller_db_user) + * [`coller_db_password`](#variable-coller_db_password) + + + + +## Role variables + +The following variables can be configured for this role: + +| Variable | Type | Required | Default | Description (abstract) | +|----------|------|----------|---------|------------------------| +| `coller_version` | `str` | No | `"1.3.1"` | Version of the binary. | +| `coller_config_dir` | `path` | No | `"/etc/coller"` | Directory of the configuration files. | +| `coller_port` | `int` | No | `8080` | Port to listen. | +| `coller_manage_iptables` | `bool` | No | `false` | Create iptables rule to allow the service. | +| `coller_allowed_sources` | `list` | No | N/A | List of allowed networks to allow.

Enabled when `coller_manage_iptables` is enabled. | +| `coller_db_name` | `str` | No | `"coller"` | Name of the database to connect. | +| `coller_db_user` | `str` | No | `"coller"` | User to connect to the database. | +| `coller_db_password` | `str` | Yes | N/A | Password to connect to the database. | + +### `coller_version` + +[*⇑ Back to ToC ⇑*](#toc) + +Version of the binary. + +- **Type**: `str` +- **Required**: No +- **Default**: `"1.3.1"` + + + +### `coller_config_dir` + +[*⇑ Back to ToC ⇑*](#toc) + +Directory of the configuration files. + +- **Type**: `path` +- **Required**: No +- **Default**: `"/etc/coller"` + + + +### `coller_port` + +[*⇑ Back to ToC ⇑*](#toc) + +Port to listen. + +- **Type**: `int` +- **Required**: No +- **Default**: `8080` + + + +### `coller_manage_iptables` + +[*⇑ Back to ToC ⇑*](#toc) + +Create iptables rule to allow the service. + +- **Type**: `bool` +- **Required**: No +- **Default**: `false` + + + +### `coller_allowed_sources` + +[*⇑ Back to ToC ⇑*](#toc) + +List of allowed networks to allow. + +Enabled when `coller_manage_iptables` is enabled. + +- **Type**: `list` +- **Required**: No + + + +### `coller_db_name` + +[*⇑ Back to ToC ⇑*](#toc) + +Name of the database to connect. + +- **Type**: `str` +- **Required**: No +- **Default**: `"coller"` + + + +### `coller_db_user` + +[*⇑ Back to ToC ⇑*](#toc) + +User to connect to the database. + +- **Type**: `str` +- **Required**: No +- **Default**: `"coller"` + + + +### `coller_db_password` + +[*⇑ Back to ToC ⇑*](#toc) + +Password to connect to the database. + +- **Type**: `str` +- **Required**: Yes + + + + + + +## Usage + +Example of a basic coller.yml playbook: + +```yaml +- hosts: coller + roles: + - coller +``` + +Then run the playbook: + +``` +ansible-playbook coller.yml +``` diff --git a/roles/coller/defaults/main.yml b/roles/coller/defaults/main.yml new file mode 100644 index 0000000..638ab7c --- /dev/null +++ b/roles/coller/defaults/main.yml @@ -0,0 +1,51 @@ +--- + +# Version of the binary. +# +# - Type: str +# - Required: No +# - Default: 1.3.1 +coller_version: 1.3.1 + +# Directory of the configuration files. +# +# - Type: path +# - Required: No +# - Default: /etc/coller +coller_config_dir: /etc/coller + +# Port to listen. +# +# - Type: int +# - Required: No +# - Default: 8080 +coller_port: 8080 + +# Create iptables rule to allow the service. +# +# - Type: bool +# - Required: No +# - Default: false +coller_manage_iptables: false + +# List of allowed networks to allow. +# +# Enabled when `coller_manage_iptables` is enabled. +# +# - Type: list +# - Required: No +coller_allowed_sources: [] + +# Name of the database to connect. +# +# - Type: str +# - Required: No +# - Default: coller +coller_db_name: coller + +# User to connect to the database. +# +# - Type: str +# - Required: No +# - Default: coller +coller_db_user: coller diff --git a/roles/coller/handlers/main.yml b/roles/coller/handlers/main.yml new file mode 100644 index 0000000..9640331 --- /dev/null +++ b/roles/coller/handlers/main.yml @@ -0,0 +1,4 @@ +--- +- name: Save iptables + ansible.builtin.shell: + cmd: netfilter-persistent save diff --git a/roles/coller/meta/argument_specs.yml b/roles/coller/meta/argument_specs.yml new file mode 100644 index 0000000..a4b4744 --- /dev/null +++ b/roles/coller/meta/argument_specs.yml @@ -0,0 +1,52 @@ +--- +argument_specs: + main: + short_description: Install and configure a coller instance + description: + - Install and configure a [coller](https://git.riou.xyz/jriou/coller) instance. + author: + - jriou + options: + coller_version: + description: + - Version of the binary. + default: "1.3.1" + + coller_config_dir: + description: + - Directory of the configuration files. + type: path + default: /etc/coller + + coller_port: + description: + - Port to listen. + type: int + default: 8080 + + coller_manage_iptables: + description: + - Create iptables rule to allow the service. + type: bool + default: false + + coller_allowed_sources: + description: + - List of allowed networks to allow. + - Enabled when `coller_manage_iptables` is enabled. + type: list + + coller_db_name: + description: + - Name of the database to connect. + default: coller + + coller_db_user: + description: + - User to connect to the database. + default: coller + + coller_db_password: + description: + - Password to connect to the database. + required: true diff --git a/roles/coller/meta/main.yml b/roles/coller/meta/main.yml new file mode 100644 index 0000000..3f5647c --- /dev/null +++ b/roles/coller/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: +- role: geerlingguy.docker diff --git a/roles/coller/tasks/main.yml b/roles/coller/tasks/main.yml new file mode 100644 index 0000000..736494c --- /dev/null +++ b/roles/coller/tasks/main.yml @@ -0,0 +1,55 @@ +--- +- name: Check variables + ansible.builtin.assert: + that: + - coller_db_password is defined + +- name: Download source code + ansible.builtin.git: + repo: https://git.riou.xyz/jriou/coller.git + dest: /opt/coller + version: "{{ coller_version }}" + +- name: Create directories + ansible.builtin.file: + path: "{{ item }}" + state: directory + owner: root + group: root + mode: "0755" + loop: + - "{{ coller_config_dir }}" + +- name: Create docker-compose files + ansible.builtin.template: + src: "{{ item.src }}.j2" + dest: "{{ coller_config_dir }}/{{ item.src }}" + owner: root + group: root + mode: "{{ item.mode }}" + loop: + - src: docker-compose.yml + mode: "0644" + - src: db.env + mode: "0600" + +- name: Create configuration file + ansible.builtin.copy: + content: + database_type: postgres + database_dsn: "host=db dbname={{ coller_db_name }} user={{ coller_db_user }} password={{ coller_db_password }}" + dest: "{{ coller_config_dir }}/collerd.json" + owner: root + group: root + mode: "0640" + no_log: true + +- name: Start service + community.docker.docker_compose_v2: + project_src: "{{ coller_config_dir }}" + files: + - docker-compose.yml + +- name: Manage iptables + when: coller_manage_iptables is truthy + ansible.builtin.include_tasks: manage-iptables.yml diff --git a/roles/coller/tasks/manage-iptables.yml b/roles/coller/tasks/manage-iptables.yml new file mode 100644 index 0000000..456b0f3 --- /dev/null +++ b/roles/coller/tasks/manage-iptables.yml @@ -0,0 +1,16 @@ +--- +- name: Install packages + ansible.builtin.package: + name: netfilter-persistent + +- name: Allow with iptables + ansible.builtin.iptables: + chain: INPUT + protocol: tcp + source: "{{ item }}" + destination_ports: + - "{{ coller_port }}" + jump: ACCEPT + comment: coller + loop: "{{ coller_allowed_sources }}" + notify: Save iptables diff --git a/roles/coller/templates/db.env.j2 b/roles/coller/templates/db.env.j2 new file mode 100644 index 0000000..511cba4 --- /dev/null +++ b/roles/coller/templates/db.env.j2 @@ -0,0 +1,6 @@ +{{ ansible_managed | comment }} +POSTGRES_USER={{ coller_db_user }} +POSTGRES_PASSWORD={{ coller_db_password }} +POSTGRES_DB={{ coller_db_name }} +POSTGRES_INITDB_ARGS="--data-checksums" +POSTGRES_HOST_AUTH_METHOD=scram-sha-256 diff --git a/roles/coller/templates/docker-compose.yml.j2 b/roles/coller/templates/docker-compose.yml.j2 new file mode 100644 index 0000000..1d46c35 --- /dev/null +++ b/roles/coller/templates/docker-compose.yml.j2 @@ -0,0 +1,32 @@ +--- +{{ ansible_managed | comment }} +services: + server: + image: coller:{{ coller_version }} + build: /opt/coller + container_name: collerd + restart: always + networks: + - coller + ports: + - "{{ coller_port }}:8080" + volumes: + - "{{ coller_config_dir }}/collerd.json:/etc/collerd.json:ro" + command: collerd -config /etc/collerd.json + + db: + image: postgres:17 + hostname: db + container_name: collerd_db + restart: always + env_file: {{ coller_config_dir }}/db.env + networks: + - coller + volumes: + - coller:/var/lib/postgresql/data + +networks: + coller: + +volumes: + coller: diff --git a/roles/firefly/README.md b/roles/firefly/README.md new file mode 100644 index 0000000..987fd40 --- /dev/null +++ b/roles/firefly/README.md @@ -0,0 +1,234 @@ +# Ansible Role Firefly + +Ansible role to manage a [Firefly III](https://firefly-iii.org/) instance. + +## Table of content + + +* [Role variables](#variables) + * [`firefly_version`](#variable-firefly_version) + * [`firefly_port`](#variable-firefly_port) + * [`firefly_static_cron_token`](#variable-firefly_static_cron_token) + * [`firefly_home`](#variable-firefly_home) + * [`firefly_site_owner`](#variable-firefly_site_owner) + * [`firefly_app_key`](#variable-firefly_app_key) + * [`firefly_language`](#variable-firefly_language) + * [`firefly_tz`](#variable-firefly_tz) + * [`firefly_db_database`](#variable-firefly_db_database) + * [`firefly_db_username`](#variable-firefly_db_username) + * [`firefly_db_password`](#variable-firefly_db_password) + * [`firefly_manage_iptables`](#variable-firefly_manage_iptables) + * [`firefly_allowed_sources`](#variable-firefly_allowed_sources) + + + +## Role variables + +The following variables can be configured for this role: + +| Variable | Type | Required | Default | Description (abstract) | +|----------|------|----------|---------|------------------------| +| `firefly_version` | `str` | No | `"latest"` | Version of the docker image. | +| `firefly_port` | `int` | No | `8080` | | +| `firefly_static_cron_token` | `str` | Yes | N/A | Token used by the cron job (sensitive). | +| `firefly_home` | `path` | No | `"/var/lib/firefly"` | Directory where to store data files. | +| `firefly_site_owner` | `str` | No | `"root@localhost"` | E-mail address of the site owner. | +| `firefly_app_key` | `str` | Yes | N/A | Application key (sensitive). | +| `firefly_language` | `str` | No | `"en_US"` | Language of the web interface. | +| `firefly_tz` | `str` | No | `"Etc/UTC"` | Time zone of the web interface. | +| `firefly_db_database` | `str` | No | `"firefly"` | Name of the database. | +| `firefly_db_username` | `str` | No | `"firefly"` | Name of the user to connect to the database. | +| `firefly_db_password` | `str` | Yes | N/A | Password to connect to the database (sensitive). | +| `firefly_manage_iptables` | `bool` | No | `false` | Configure iptables rules. | +| `firefly_allowed_sources` | `list` | No | N/A | List of IP ranges to allow when `firefly_manage_iptables` is enabled. | + +### `firefly_version` + +[*⇑ Back to ToC ⇑*](#toc) + +Version of the docker image. + +- **Type**: `str` +- **Required**: No +- **Default**: `"latest"` + + + +### `firefly_port` + +[*⇑ Back to ToC ⇑*](#toc) + + + +- **Type**: `int` +- **Required**: No +- **Default**: `8080` + + + +### `firefly_static_cron_token` + +[*⇑ Back to ToC ⇑*](#toc) + +Token used by the cron job (sensitive). + +- **Type**: `str` +- **Required**: Yes + + + +### `firefly_home` + +[*⇑ Back to ToC ⇑*](#toc) + +Directory where to store data files. + +- **Type**: `path` +- **Required**: No +- **Default**: `"/var/lib/firefly"` + + + +### `firefly_site_owner` + +[*⇑ Back to ToC ⇑*](#toc) + +E-mail address of the site owner. + +- **Type**: `str` +- **Required**: No +- **Default**: `"root@localhost"` + + + +### `firefly_app_key` + +[*⇑ Back to ToC ⇑*](#toc) + +Application key (sensitive). + +- **Type**: `str` +- **Required**: Yes + + + +### `firefly_language` + +[*⇑ Back to ToC ⇑*](#toc) + +Language of the web interface. + +- **Type**: `str` +- **Required**: No +- **Default**: `"en_US"` + + + +### `firefly_tz` + +[*⇑ Back to ToC ⇑*](#toc) + +Time zone of the web interface. + +- **Type**: `str` +- **Required**: No +- **Default**: `"Etc/UTC"` + + + +### `firefly_db_database` + +[*⇑ Back to ToC ⇑*](#toc) + +Name of the database. + +- **Type**: `str` +- **Required**: No +- **Default**: `"firefly"` + + + +### `firefly_db_username` + +[*⇑ Back to ToC ⇑*](#toc) + +Name of the user to connect to the database. + +- **Type**: `str` +- **Required**: No +- **Default**: `"firefly"` + + + +### `firefly_db_password` + +[*⇑ Back to ToC ⇑*](#toc) + +Password to connect to the database (sensitive). + +- **Type**: `str` +- **Required**: Yes + + + +### `firefly_manage_iptables` + +[*⇑ Back to ToC ⇑*](#toc) + +Configure iptables rules. + +- **Type**: `bool` +- **Required**: No +- **Default**: `false` + + + +### `firefly_allowed_sources` + +[*⇑ Back to ToC ⇑*](#toc) + +List of IP ranges to allow when `firefly_manage_iptables` is enabled. + +- **Type**: `list` +- **Required**: No + + + + + + +## Configuration + +See [Variable +precedence](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_variables.html#ansible-variable-precedence) +to find where you should put your own variables. + +Then define at least `firefly_static_cron_token`, `firefly_db_password` and +`firefly_app_key` variables with a strong and secure password, encrypted using +[ansible-vault](https://docs.ansible.com/ansible/latest/cli/ansible-vault.html). + +See list of [default variables](defaults/main.yml). + + +## Usage + +Example of a basic firefly.yml playbook: + +```yaml +hosts: + - firefly + +roles: + - firefly +``` + +Then run the playbook: + +``` +ansible-playbook firefly.yml +``` + +## Donate + +As we all love FOSS projects, you should consider [sponsoring and/or +contribute](https://github.com/firefly-iii/firefly-iii). diff --git a/roles/firefly/defaults/main.yml b/roles/firefly/defaults/main.yml new file mode 100644 index 0000000..96a2f4e --- /dev/null +++ b/roles/firefly/defaults/main.yml @@ -0,0 +1,66 @@ +--- +firefly_port: 8080 + +# Version of the docker image. +# +# - Type: str +# - Required: No +# - Default: latest +firefly_version: latest + +# Directory where to store data files. +# +# - Type: path +# - Required: No +# - Default: /var/lib/firefly +firefly_home: /var/lib/firefly + +# E-mail address of the site owner. +# +# - Type: str +# - Required: No +# - Default: root@localhost +firefly_site_owner: root@localhost + + +# Language of the web interface. +# +# - Type: str +# - Required: No +# - Default: en_US +firefly_language: en_US + +# Time zone of the web interface. +# +# - Type: str +# - Required: No +# - Default: Etc/UTC +firefly_tz: Etc/UTC + +# Name of the database. +# +# - Type: str +# - Required: No +# - Default: firefly +firefly_db_database: firefly + +# Name of the user to connect to the database. +# +# - Type: str +# - Required: No +# - Default: firefly +firefly_db_username: firefly + + +# Configure iptables rules. +# +# - Type: bool +# - Required: No +# - Default: false +firefly_manage_iptables: false + +# List of IP ranges to allow when `firefly_manage_iptables` is enabled. +# +# - Type: list +# - Required: No +firefly_allowed_sources: [] diff --git a/roles/firefly/handlers/main.yml b/roles/firefly/handlers/main.yml new file mode 100644 index 0000000..9640331 --- /dev/null +++ b/roles/firefly/handlers/main.yml @@ -0,0 +1,4 @@ +--- +- name: Save iptables + ansible.builtin.shell: + cmd: netfilter-persistent save diff --git a/roles/firefly/meta/argument_specs.yml b/roles/firefly/meta/argument_specs.yml new file mode 100644 index 0000000..c87f062 --- /dev/null +++ b/roles/firefly/meta/argument_specs.yml @@ -0,0 +1,76 @@ +--- +argument_specs: + main: + short_description: Install and configure Firefly III + description: + - Install and configure [Firefly III](https://www.firefly-iii.org/). + author: + - jriou + options: + firefly_version: + description: + - Version of the docker image. + default: latest + + firefly_port: + descritpion: + - Port to listen. + type: int + default: 8080 + + firefly_static_cron_token: + description: + - Token used by the cron job (sensitive). + required: true + + firefly_home: + description: + - Directory where to store data files. + type: path + default: /var/lib/firefly + + firefly_site_owner: + description: + - E-mail address of the site owner. + default: root@localhost + + firefly_app_key: + description: + - Application key (sensitive). + required: true + + firefly_language: + description: + - Language of the web interface. + default: en_US + + firefly_tz: + description: + - Time zone of the web interface. + default: Etc/UTC + + firefly_db_database: + description: + - Name of the database. + default: firefly + + firefly_db_username: + description: + - Name of the user to connect to the database. + default: firefly + + firefly_db_password: + description: + - Password to connect to the database (sensitive). + required: true + + firefly_manage_iptables: + description: + - Configure iptables rules. + type: bool + default: false + + firefly_allowed_sources: + description: + - List of IP ranges to allow when `firefly_manage_iptables` is enabled. + type: list diff --git a/roles/firefly/meta/main.yml b/roles/firefly/meta/main.yml new file mode 100644 index 0000000..3f5647c --- /dev/null +++ b/roles/firefly/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: +- role: geerlingguy.docker diff --git a/roles/firefly/tasks/main.yml b/roles/firefly/tasks/main.yml new file mode 100644 index 0000000..8d44a22 --- /dev/null +++ b/roles/firefly/tasks/main.yml @@ -0,0 +1,47 @@ +--- +- name: Check requirements + ansible.builtin.assert: + that: + - firefly_static_cron_token is defined + - firefly_db_password is defined + - firefly_app_key is defined + +- name: Install dependencies + ansible.builtin.apt: + name: + - python3-docker + - python3-compose + +- name: Create directories + ansible.builtin.file: + path: /etc/firefly + state: directory + +- name: Create configuration files + ansible.builtin.template: + src: "{{ item }}.j2" + dest: "/etc/firefly/{{ item }}" + mode: "0600" + loop: + - docker-compose.yml + - db.env + - app.env + +- name: Start service + community.docker.docker_compose_v2: + project_src: /etc/firefly + files: + - docker-compose.yml + +- name: Allow with iptables + ansible.builtin.iptables: + chain: INPUT + protocol: tcp + source: "{{ item }}" + destination_ports: + - "{{ firefly_port }}" + jump: ACCEPT + comment: firefly + loop: "{{ firefly_allowed_sources }}" + notify: Save iptables + when: firefly_manage_iptables is truthy diff --git a/roles/firefly/templates/app.env.j2 b/roles/firefly/templates/app.env.j2 new file mode 100644 index 0000000..89aa8aa --- /dev/null +++ b/roles/firefly/templates/app.env.j2 @@ -0,0 +1,132 @@ +APP_ENV=local +APP_DEBUG=false + +SITE_OWNER={{ firefly_site_owner }} + +APP_KEY={{ firefly_app_key }} + +DEFAULT_LANGUAGE={{ firefly_language }} +DEFAULT_LOCALE=equal + +TZ={{ firefly_tz }} + +TRUSTED_PROXIES=* + +LOG_CHANNEL=stack + +APP_LOG_LEVEL=notice + +AUDIT_LOG_LEVEL=emergency +AUDIT_LOG_CHANNEL= +PAPERTRAIL_HOST= +PAPERTRAIL_PORT= + +# Database credentials. Make sure the database exists. I recommend a dedicated user for Firefly III +# For other database types, please see the FAQ: https://docs.firefly-iii.org/firefly-iii/faq/self-hosted/#i-want-to-use-sqlite +# If you use Docker or similar, you can set these variables from a file by appending them with _FILE +# Use "pgsql" for PostgreSQL +# Use "mysql" for MySQL and MariaDB. +# Use "sqlite" for SQLite. +DB_CONNECTION=pgsql +DB_HOST=db +DB_PORT=5432 +DB_DATABASE={{ firefly_db_database }} +DB_USERNAME={{ firefly_db_username }} +DB_PASSWORD={{ firefly_db_password }} +DB_SOCKET= + +PGSQL_SSL_MODE=prefer +PGSQL_SCHEMA=public + +CACHE_DRIVER=file +SESSION_DRIVER=file + +REDIS_SCHEME=tcp +REDIS_PATH= +REDIS_HOST=redis +REDIS_PORT=6379 +REDIS_USERNAME=firefly +REDIS_PASSWORD= +REDIS_DB="0" +REDIS_CACHE_DB="1" + +COOKIE_PATH="/" +COOKIE_DOMAIN= +COOKIE_SECURE=false +COOKIE_SAMESITE=lax + +MAIL_MAILER=log +MAIL_HOST=null +MAIL_PORT=2525 +MAIL_FROM=changeme@example.com +MAIL_USERNAME=null +MAIL_PASSWORD=null +MAIL_ENCRYPTION=null +MAIL_SENDMAIL_COMMAND= +MAILGUN_DOMAIN= +MAILGUN_SECRET= +MAILGUN_ENDPOINT=api.mailgun.net +MANDRILL_SECRET= +SPARKPOST_SECRET= +SEND_ERROR_MESSAGE=true +SEND_REPORT_JOURNALS=true + +ENABLE_EXTERNAL_MAP=false +ENABLE_EXTERNAL_RATES=false +MAP_DEFAULT_LAT=51.983333 +MAP_DEFAULT_LONG=5.916667 +MAP_DEFAULT_ZOOM=6 + +VALID_URL_PROTOCOLS= + +AUTHENTICATION_GUARD=web +AUTHENTICATION_GUARD_HEADER=REMOTE_USER +AUTHENTICATION_GUARD_EMAIL= + +PASSPORT_PRIVATE_KEY= +PASSPORT_PUBLIC_KEY= + +CUSTOM_LOGOUT_URL= + +DISABLE_FRAME_HEADER=false +DISABLE_CSP_HEADER=false +TRACKER_SITE_ID= +TRACKER_URL= + +ALLOW_WEBHOOKS=false + +STATIC_CRON_TOKEN={{ firefly_static_cron_token }} + +DKR_BUILD_LOCALE=false +DKR_CHECK_SQLITE=true +DKR_RUN_MIGRATION=true +DKR_RUN_UPGRADE=true +DKR_RUN_VERIFY=true +DKR_RUN_REPORT=true +DKR_RUN_PASSPORT_INSTALL=true + +APP_NAME=FireflyIII +BROADCAST_DRIVER=log +QUEUE_DRIVER=sync +CACHE_PREFIX=firefly +PUSHER_KEY= +IPINFO_TOKEN= +PUSHER_SECRET= +PUSHER_ID= +DEMO_USERNAME= +DEMO_PASSWORD= +FIREFLY_III_LAYOUT=v1 + +# +# If you have trouble configuring your Firefly III installation, DON'T BOTHER setting this variable. +# It won't work. It doesn't do ANYTHING. Don't believe the lies you read online. I'm not joking. +# This configuration value WILL NOT HELP. +# +# Notable exception to this rule is Synology, which, according to some users, will use APP_URL to rewrite stuff. +# +# This variable is ONLY used in some of the emails Firefly III sends around. Nowhere else. +# So when configuring anything WEB related this variable doesn't do anything. Nothing +# +# If you're stuck I understand you get desperate but look SOMEWHERE ELSE. +# +APP_URL=http://localhost diff --git a/roles/firefly/templates/db.env.j2 b/roles/firefly/templates/db.env.j2 new file mode 100644 index 0000000..6805c19 --- /dev/null +++ b/roles/firefly/templates/db.env.j2 @@ -0,0 +1,5 @@ +POSTGRES_USER={{ firefly_db_username }} +POSTGRES_PASSWORD={{ firefly_db_password }} +POSTGRES_DB={{ firefly_db_database }} +POSTGRES_INITDB_ARGS="--data-checksums" +POSTGRES_HOST_AUTH_METHOD=scram-sha-256 diff --git a/roles/firefly/templates/docker-compose.yml.j2 b/roles/firefly/templates/docker-compose.yml.j2 new file mode 100644 index 0000000..81ae8f0 --- /dev/null +++ b/roles/firefly/templates/docker-compose.yml.j2 @@ -0,0 +1,40 @@ +--- +{{ ansible_managed | comment }} +services: + app: + image: fireflyiii/core:{{ firefly_version }} + hostname: app + container_name: firefly_iii_core + restart: always + volumes: + - {{ firefly_home }}/app/upload:/var/www/html/storage/upload + env_file: /etc/firefly/app.env + networks: + - firefly_iii + ports: + - {{ firefly_port }}:8080 + depends_on: + - db + db: + image: postgres:17 + hostname: db + container_name: firefly_iii_db + restart: always + env_file: /etc/firefly/db.env + networks: + - firefly_iii + volumes: + - {{ firefly_home }}/db/data:/var/lib/postgresql/data + - {{ firefly_home }}/db/backup:/var/lib/postgresql/backup + + cron: + image: alpine + restart: always + container_name: firefly_iii_cron + command: sh -c "echo \"0 3 * * * wget -qO- http://app:8080/api/v1/cron/{{ firefly_static_cron_token }}\" | crontab - && crond -f -L /dev/stdout" + networks: + - firefly_iii + +networks: + firefly_iii: + driver: bridge diff --git a/roles/forgejo/README.md b/roles/forgejo/README.md new file mode 100644 index 0000000..b5d0404 --- /dev/null +++ b/roles/forgejo/README.md @@ -0,0 +1,239 @@ +# Ansible Role Forgejo + +Ansible role to manage a [Forgejo](https://forgejo.org/) instance. + +## Configuration + +See [Variable +precedence](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_variables.html#ansible-variable-precedence) +to find where you should put your own variables. + +Then define at least `forgejo_db_password` with a strong and secure password, +encrypted using +[ansible-vault](https://docs.ansible.com/ansible/latest/cli/ansible-vault.html). + + +## Table of Content + + +* [Role variables](#variables) + * [`forgejo_version`](#variable-forgejo_version) + * [`forgejo_user`](#variable-forgejo_user) + * [`forgejo_home_dir`](#variable-forgejo_home_dir) + * [`forgejo_config_dir`](#variable-forgejo_config_dir) + * [`forgejo_web_port`](#variable-forgejo_web_port) + * [`forgejo_ssh_port`](#variable-forgejo_ssh_port) + * [`forgejo_db_username`](#variable-forgejo_db_username) + * [`forgejo_db_password`](#variable-forgejo_db_password) + * [`forgejo_db_database`](#variable-forgejo_db_database) + * [`forgejo_mailer`](#variable-forgejo_mailer) + * [`forgejo_service`](#variable-forgejo_service) + * [`forgejo_manage_iptables`](#variable-forgejo_manage_iptables) + * [`forgejo_allowed_sources`](#variable-forgejo_allowed_sources) + + + +## Role variables + +The following variables can be configured for this role: + +| Variable | Type | Required | Default | Description (abstract) | +|----------|------|----------|---------|------------------------| +| `forgejo_version` | `int` | No | `14` | Version of the Forgejo binaries | +| `forgejo_user` | `path` | No | `"forgejo"` | Operating system user to run the server | +| `forgejo_home_dir` | `path` | No | `"/var/lib/forgejo"` | Path to the home directory | +| `forgejo_config_dir` | `path` | No | `"/etc/forgejo"` | Path to the configuration directory | +| `forgejo_web_port` | `int` | No | `3000` | Port to listen for the web UI | +| `forgejo_ssh_port` | `int` | No | `222` | Port to listen for SSH | +| `forgejo_db_username` | `str` | No | `"forgejo"` | Name of the user in the database | +| `forgejo_db_password` | `str` | Yes | N/A | Password of the user in the database | +| `forgejo_db_database` | `str` | No | `"forgejo"` | Name of the database | +| `forgejo_mailer` | `dict` | No | N/A | Configure the mailer to send e-mail notifications

Define a `enabled` key with a boolean to enable the mailer

Define a `from` key with the source e-mail address

See [Email setup](https://forgejo.org/docs/latest/admin/setup/email/) | +| `forgejo_service` | `dict` | No | N/A | Configure service settings

See [Service](https://forgejo.org/docs/latest/admin/config-cheat-sheet/#service-service) | +| `forgejo_manage_iptables` | `bool` | No | `false` | Configure iptables rules | +| `forgejo_allowed_sources` | `list` | No | N/A | List of IP ranges to allow when `forgejo_manage_iptables` is enabled | + +### `forgejo_version` + +[*⇑ Back to ToC ⇑*](#toc) + +Version of the Forgejo binaries + +- **Type**: `int` +- **Required**: No +- **Default**: `14` + + + +### `forgejo_user` + +[*⇑ Back to ToC ⇑*](#toc) + +Operating system user to run the server + +- **Type**: `path` +- **Required**: No +- **Default**: `"forgejo"` + + + +### `forgejo_home_dir` + +[*⇑ Back to ToC ⇑*](#toc) + +Path to the home directory + +- **Type**: `path` +- **Required**: No +- **Default**: `"/var/lib/forgejo"` + + + +### `forgejo_config_dir` + +[*⇑ Back to ToC ⇑*](#toc) + +Path to the configuration directory + +- **Type**: `path` +- **Required**: No +- **Default**: `"/etc/forgejo"` + + + +### `forgejo_web_port` + +[*⇑ Back to ToC ⇑*](#toc) + +Port to listen for the web UI + +- **Type**: `int` +- **Required**: No +- **Default**: `3000` + + + +### `forgejo_ssh_port` + +[*⇑ Back to ToC ⇑*](#toc) + +Port to listen for SSH + +- **Type**: `int` +- **Required**: No +- **Default**: `222` + + + +### `forgejo_db_username` + +[*⇑ Back to ToC ⇑*](#toc) + +Name of the user in the database + +- **Type**: `str` +- **Required**: No +- **Default**: `"forgejo"` + + + +### `forgejo_db_password` + +[*⇑ Back to ToC ⇑*](#toc) + +Password of the user in the database + +- **Type**: `str` +- **Required**: Yes + + + +### `forgejo_db_database` + +[*⇑ Back to ToC ⇑*](#toc) + +Name of the database + +- **Type**: `str` +- **Required**: No +- **Default**: `"forgejo"` + + + +### `forgejo_mailer` + +[*⇑ Back to ToC ⇑*](#toc) + +Configure the mailer to send e-mail notifications + +Define a `enabled` key with a boolean to enable the mailer + +Define a `from` key with the source e-mail address + +See [Email setup](https://forgejo.org/docs/latest/admin/setup/email/) + +- **Type**: `dict` +- **Required**: No + + + +### `forgejo_service` + +[*⇑ Back to ToC ⇑*](#toc) + +Configure service settings + +See [Service](https://forgejo.org/docs/latest/admin/config-cheat-sheet/#service-service) + +- **Type**: `dict` +- **Required**: No + + + +### `forgejo_manage_iptables` + +[*⇑ Back to ToC ⇑*](#toc) + +Configure iptables rules + +- **Type**: `bool` +- **Required**: No +- **Default**: `false` + + + +### `forgejo_allowed_sources` + +[*⇑ Back to ToC ⇑*](#toc) + +List of IP ranges to allow when `forgejo_manage_iptables` is enabled + +- **Type**: `list` +- **Required**: No + + + + + + +## Usage + +Example of a basic forgejo.yml playbook: + +```yaml +- hosts: forgejo + roles: + - forgejo +``` + +Then run the playbook: + +``` +ansible-playbook forgejo.yml +``` + +## Donate + +As we all love FOSS projects, you should consider [donating to +Codeberg](https://donate.codeberg.org/), the non-profit organization behind +Forgejo. diff --git a/roles/forgejo/defaults/main.yml b/roles/forgejo/defaults/main.yml new file mode 100644 index 0000000..e494b70 --- /dev/null +++ b/roles/forgejo/defaults/main.yml @@ -0,0 +1,91 @@ +--- + +# Version of the Forgejo binaries +# +# - Type: int +# - Required: No +# - Default: 14 +forgejo_version: 14 + + +# Operating system user to run the server +# +# - Type: path +# - Required: No +# - Default: forgejo +forgejo_user: forgejo + +# Path to the home directory +# +# - Type: path +# - Required: No +# - Default: /var/lib/forgejo +forgejo_home_dir: /var/lib/forgejo + +# Path to the configuration directory +# +# - Type: path +# - Required: No +# - Default: /etc/forgejo +forgejo_config_dir: /etc/forgejo + +# Port to listen for the web UI +# +# - Type: int +# - Required: No +# - Default: 3000 +forgejo_web_port: 3000 + +# Port to listen for SSH +# +# - Type: int +# - Required: No +# - Default: 222 +forgejo_ssh_port: 222 + +# Name of the user in the database +# +# - Type: str +# - Required: No +# - Default: forgejo +forgejo_db_username: forgejo + +# Name of the database +# +# - Type: str +# - Required: No +# - Default: forgejo +forgejo_db_database: forgejo + +# Configure the mailer to send e-mail notifications +# +# Define a `enabled` key with a boolean to enable the mailer +# +# Define a `from` key with the source e-mail address +# +# See +# +# - Type: dict +# - Required: No +forgejo_mailer: {} + +# Configure service settings +# +# See +# +# - Type: dict +# - Required: No +forgejo_service: {} + +# Configure iptables rules +# +# - Type: bool +# - Required: No +# - Default: false +forgejo_manage_iptables: false + +# List of IP ranges to allow when `forgejo_manage_iptables` is enabled +# +# - Type: list +# - Required: No +forgejo_allowed_sources: [] diff --git a/roles/forgejo/handlers/main.yml b/roles/forgejo/handlers/main.yml new file mode 100644 index 0000000..9640331 --- /dev/null +++ b/roles/forgejo/handlers/main.yml @@ -0,0 +1,4 @@ +--- +- name: Save iptables + ansible.builtin.shell: + cmd: netfilter-persistent save diff --git a/roles/forgejo/meta/argument_specs.yml b/roles/forgejo/meta/argument_specs.yml new file mode 100644 index 0000000..f153919 --- /dev/null +++ b/roles/forgejo/meta/argument_specs.yml @@ -0,0 +1,84 @@ +--- +argument_specs: + main: + short_description: Install and configure a Forgejo instance + description: + - Install and configure a [Forgejo](https://forgejo.org/) instance. + author: + - jriou + options: + forgejo_version: + description: + - Version of the Forgejo binaries + type: int + default: 14 + + forgejo_user: + description: + - Operating system user to run the server + type: path + default: forgejo + + forgejo_home_dir: + description: + - Path to the home directory + type: path + default: /var/lib/forgejo + + forgejo_config_dir: + description: + - Path to the configuration directory + type: path + default: /etc/forgejo + + forgejo_web_port: + description: + - Port to listen for the web UI + type: int + default: 3000 + + forgejo_ssh_port: + description: + - Port to listen for SSH + type: int + default: 222 + + forgejo_db_username: + description: + - Name of the user in the database + default: forgejo + + forgejo_db_password: + description: + - Password of the user in the database + required: true + + forgejo_db_database: + description: + - Name of the database + default: forgejo + + forgejo_mailer: + description: + - Configure the mailer to send e-mail notifications + - Define a `enabled` key with a boolean to enable the mailer + - Define a `from` key with the source e-mail address + - See [Email setup](https://forgejo.org/docs/latest/admin/setup/email/) + type: dict + + forgejo_service: + description: + - Configure service settings + - See [Service](https://forgejo.org/docs/latest/admin/config-cheat-sheet/#service-service) + type: dict + + forgejo_manage_iptables: + description: + - Configure iptables rules + type: bool + default: false + + forgejo_allowed_sources: + description: + - List of IP ranges to allow when `forgejo_manage_iptables` is enabled + type: list diff --git a/roles/forgejo/meta/main.yml b/roles/forgejo/meta/main.yml new file mode 100644 index 0000000..3f5647c --- /dev/null +++ b/roles/forgejo/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: +- role: geerlingguy.docker diff --git a/roles/forgejo/tasks/main.yml b/roles/forgejo/tasks/main.yml new file mode 100644 index 0000000..0a90aba --- /dev/null +++ b/roles/forgejo/tasks/main.yml @@ -0,0 +1,72 @@ +--- +- name: Check required variables + ansible.builtin.assert: + that: + - forgejo_db_password is defined + +- name: Create user + ansible.builtin.user: + name: "{{ forgejo_user }}" + system: true + password: '!' + home: "{{ forgejo_home_dir }}" + create_home: false + +- name: Read attributes + ansible.builtin.getent: + database: passwd + key: "{{ forgejo_user }}" + +- name: Create directories + ansible.builtin.file: + state: directory + path: "{{ item }}" + owner: "{{ forgejo_user }}" + group: "{{ forgejo_user }}" + mode: "0755" + loop: &forgejo_directories + - "{{ forgejo_config_dir }}" + - "{{ forgejo_home_dir }}" + - "{{ forgejo_home_dir }}/server" + - "{{ forgejo_home_dir }}/db" + +- name: Ensure permissions on the directories + ansible.builtin.command: + cmd: "chown -v -R {{ forgejo_user }}:{{ forgejo_user }} {{ item }}" + loop: *forgejo_directories + register: forgejo_chown + changed_when: forgejo_chown.stdout_lines | regex_search('^changed ownership of') != None + +- name: Create docker-compose configuration + ansible.builtin.template: + src: "{{ item.name }}.j2" + dest: "{{ forgejo_config_dir }}/{{ item.name }}" + owner: "{{ forgejo_user }}" + group: "{{ forgejo_user }}" + mode: "{{ item.mode }}" + loop: + - name: docker-compose.yml + mode: "0644" + - name: server.env + mode: "0600" + - name: db.env + mode: "0600" + +- name: Start service + community.docker.docker_compose_v2: + project_src: "{{ forgejo_config_dir }}" + files: + - docker-compose.yml + +- name: Allow with iptables + ansible.builtin.iptables: + chain: INPUT + protocol: tcp + source: "{{ item }}" + destination_ports: + - "{{ forgejo_web_port }}" + - "{{ forgejo_ssh_port }}" + jump: ACCEPT + comment: forgejo + loop: "{{ forgejo_allowed_sources }}" + when: forgejo_manage_iptables is truthy diff --git a/roles/forgejo/templates/db.env.j2 b/roles/forgejo/templates/db.env.j2 new file mode 100644 index 0000000..ba5ecbd --- /dev/null +++ b/roles/forgejo/templates/db.env.j2 @@ -0,0 +1,6 @@ +{{ ansible_managed | comment }} +POSTGRES_USER="{{ forgejo_db_username }}" +POSTGRES_PASSWORD="{{ forgejo_db_password }}" +POSTGRES_DB="{{ forgejo_db_database }}" +POSTGRES_INITDB_ARGS="--data-checksums" +POSTGRES_HOST_AUTH_METHOD=scram-sha-256 diff --git a/roles/forgejo/templates/docker-compose.yml.j2 b/roles/forgejo/templates/docker-compose.yml.j2 new file mode 100644 index 0000000..d54e1d7 --- /dev/null +++ b/roles/forgejo/templates/docker-compose.yml.j2 @@ -0,0 +1,35 @@ +--- +{{ ansible_managed | comment }} +services: + server: + image: codeberg.org/forgejo/forgejo:{{ forgejo_version }} + container_name: forgejo-server + env_file: {{ forgejo_config_dir }}/server.env + restart: always + networks: + - forgejo + volumes: + - "{{ forgejo_home_dir }}/server:/data" + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + ports: + - "{{ forgejo_web_port }}:3000" + - "{{ forgejo_ssh_port }}:22" + depends_on: + - db + + db: + image: postgres:17 + hostname: db + container_name: forgejo-db + restart: always + env_file: {{ forgejo_config_dir }}/db.env + user: "{{ ansible_facts.getent_passwd.forgejo[1] }}:{{ ansible_facts.getent_passwd.forgejo[2] }}" + networks: + - forgejo + volumes: + - "{{ forgejo_home_dir }}/db:/var/lib/postgresql/data" + +networks: + forgejo: + external: false diff --git a/roles/forgejo/templates/server.env.j2 b/roles/forgejo/templates/server.env.j2 new file mode 100644 index 0000000..0bf2d4c --- /dev/null +++ b/roles/forgejo/templates/server.env.j2 @@ -0,0 +1,19 @@ +{{ ansible_managed | comment }} +USER_UID={{ ansible_facts.getent_passwd.forgejo[1] }} +USER_GID={{ ansible_facts.getent_passwd.forgejo[2] }} +FORGEJO__server__SSH_PORT={{ forgejo_ssh_port }} +FORGEJO__database__DB_TYPE=postgres +FORGEJO__database__HOST=db:5432 +FORGEJO__database__NAME="{{ forgejo_db_database }}" +FORGEJO__database__USER="{{ forgejo_db_username }}" +FORGEJO__database__PASSWD="{{ forgejo_db_password }}" +{% if forgejo_mailer %} +{% for k, v in forgejo_mailer.items() %} +FORGEJO__mailer__{{ k | upper }}="{{ v }}" +{% endfor %} +{% endif %} +{% if forgejo_service %} +{% for k, v in forgejo_service.items() %} +FORGEJO__service__{{ k | upper }}="{{ v }}" +{% endfor %} +{% endif %} diff --git a/roles/forgejo_runners/README.md b/roles/forgejo_runners/README.md new file mode 100644 index 0000000..c95de74 --- /dev/null +++ b/roles/forgejo_runners/README.md @@ -0,0 +1,146 @@ +# Ansible Role Forgejo Runners + +Ansible role to manage [Forgejo](https://forgejo.org/) runners. + +## Configuration + +See [Variable +precedence](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_variables.html#ansible-variable-precedence) +to find where you should put your own variables. + +Then define at least `forgejo_db_password` with a strong and secure password, +encrypted using +[ansible-vault](https://docs.ansible.com/ansible/latest/cli/ansible-vault.html). + + +## Table of Content + + +* [Role variables](#variables) + * [`forgejo_runners_version`](#variable-forgejo_runners_version) + * [`forgejo_runners_user`](#variable-forgejo_runners_user) + * [`forgejo_runners_home_dir`](#variable-forgejo_runners_home_dir) + * [`forgejo_runners_config_dir`](#variable-forgejo_runners_config_dir) + * [`forgejo_runners_instance`](#variable-forgejo_runners_instance) + * [`forgejo_runners_settings`](#variable-forgejo_runners_settings) + + + +## Role variables + +The following variables can be configured for this role: + +| Variable | Type | Required | Default | Description (abstract) | +|----------|------|----------|---------|------------------------| +| `forgejo_runners_version` | `str` | No | `"9.1.1"` | Version of the runners | +| `forgejo_runners_user` | `str` | No | `"forgejo"` | Operating system user to run the runners | +| `forgejo_runners_home_dir` | `str` | No | `"/var/lib/forgejo"` | Home directory of the operating system user | +| `forgejo_runners_config_dir` | `path` | No | `"/etc/forgejo-runners"` | Path to the configuration directory of the runners | +| `forgejo_runners_instance` | `str` | No | N/A | URL of the Forgejo instance to register the runners | +| `forgejo_runners_settings` | `dict` | No | N/A | Dict of runners to configure

The key is the name of the repository on the instance

The value is a dict with a `token` key and optionally a dict of `labels` | + +### `forgejo_runners_version` + +[*⇑ Back to ToC ⇑*](#toc) + +Version of the runners + +- **Type**: `str` +- **Required**: No +- **Default**: `"9.1.1"` + + + +### `forgejo_runners_user` + +[*⇑ Back to ToC ⇑*](#toc) + +Operating system user to run the runners + +- **Type**: `str` +- **Required**: No +- **Default**: `"forgejo"` + + + +### `forgejo_runners_home_dir` + +[*⇑ Back to ToC ⇑*](#toc) + +Home directory of the operating system user + +- **Type**: `str` +- **Required**: No +- **Default**: `"/var/lib/forgejo"` + + + +### `forgejo_runners_config_dir` + +[*⇑ Back to ToC ⇑*](#toc) + +Path to the configuration directory of the runners + +- **Type**: `path` +- **Required**: No +- **Default**: `"/etc/forgejo-runners"` + + + +### `forgejo_runners_instance` + +[*⇑ Back to ToC ⇑*](#toc) + +URL of the Forgejo instance to register the runners + +- **Type**: `str` +- **Required**: No + + + +### `forgejo_runners_settings` + +[*⇑ Back to ToC ⇑*](#toc) + +Dict of runners to configure + +The key is the name of the repository on the instance + +The value is a dict with a `token` key and optionally a dict of `labels` + +- **Type**: `dict` +- **Required**: No + + + + + + +## Usage + +Example of a basic playbook: + +```yaml +- hosts: forgejo_runners + roles: + - forgejo_runners + vars: + forgejo_runners_instance: https://codeberg.org # FIXME + forgejo_runners: + my_runner: + token: **redacted** + labels: + node-latest: docker://data.forgejo.org/oci/node:latest +``` + +Then run the playbook: + +``` +ansible-playbook forgejo_runners.yml +``` + +## Donate + +As we all love FOSS projects, you should consider [donating to +Codeberg](https://donate.codeberg.org/), the non-profit organization behind +Forgejo. diff --git a/roles/forgejo_runners/defaults/main.yml b/roles/forgejo_runners/defaults/main.yml new file mode 100644 index 0000000..391f088 --- /dev/null +++ b/roles/forgejo_runners/defaults/main.yml @@ -0,0 +1,39 @@ +--- + +# Version of the runners +# +# - Type: str +# - Required: No +# - Default: 9.1.1 +forgejo_runners_version: 9.1.1 + +# Path to the configuration directory of the runners +# +# - Type: path +# - Required: No +# - Default: /etc/forgejo-runners +forgejo_runners_config_dir: /etc/forgejo-runners + +# Dict of runners to configure +# +# The key is the name of the repository on the instance +# +# The value is a dict with a `token` key and optionally a dict of `labels` +# +# - Type: dict +# - Required: No +forgejo_runners_settings: {} + +# Operating system user to run the runners +# +# - Type: str +# - Required: No +# - Default: forgejo +forgejo_runners_user: forgejo + +# Home directory of the operating system user +# +# - Type: str +# - Required: No +# - Default: /var/lib/forgejo +forgejo_runners_home_dir: /var/lib/forgejo diff --git a/roles/forgejo_runners/handlers/main.yml b/roles/forgejo_runners/handlers/main.yml new file mode 100644 index 0000000..e27abb5 --- /dev/null +++ b/roles/forgejo_runners/handlers/main.yml @@ -0,0 +1,13 @@ +--- +- name: Start runners + community.docker.docker_compose_v2: + project_src: "{{ forgejo_runners_config_dir }}" + files: + - docker-compose.yml + +- name: Restart runners + community.docker.docker_compose_v2: + project_src: "{{ forgejo_runners_config_dir }}" + files: + - docker-compose.yml + state: restarted diff --git a/roles/forgejo_runners/meta/argument_specs.yml b/roles/forgejo_runners/meta/argument_specs.yml new file mode 100644 index 0000000..39f9e0a --- /dev/null +++ b/roles/forgejo_runners/meta/argument_specs.yml @@ -0,0 +1,40 @@ +--- +argument_specs: + main: + short_description: Install and configure Forgejo runners + description: + - Install and configure [Forgejo](https://forgejo.org/) runners. + author: + - jriou + options: + forgejo_runners_version: + description: + - Version of the runners + default: 9.1.1 + + forgejo_runners_user: + description: + - Operating system user to run the runners + default: forgejo + + forgejo_runners_home_dir: + description: + - Home directory of the operating system user + default: /var/lib/forgejo + + forgejo_runners_config_dir: + description: + - Path to the configuration directory of the runners + type: path + default: /etc/forgejo-runners + + forgejo_runners_instance: + description: + - URL of the Forgejo instance to register the runners + + forgejo_runners_settings: + description: + - Dict of runners to configure + - The key is the name of the repository on the instance + - The value is a dict with a `token` key and optionally a dict of `labels` + type: dict diff --git a/roles/forgejo_runners/meta/main.yml b/roles/forgejo_runners/meta/main.yml new file mode 100644 index 0000000..3f5647c --- /dev/null +++ b/roles/forgejo_runners/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: +- role: geerlingguy.docker diff --git a/roles/forgejo_runners/tasks/main.yml b/roles/forgejo_runners/tasks/main.yml new file mode 100644 index 0000000..490d84b --- /dev/null +++ b/roles/forgejo_runners/tasks/main.yml @@ -0,0 +1,33 @@ +--- +- name: Create user + ansible.builtin.user: + name: "{{ forgejo_runners_user }}" + system: true + password: '!' + home: "{{ forgejo_runners_home_dir }}" + create_home: false + +- name: Read attributes + ansible.builtin.getent: + database: passwd + key: "{{ forgejo_runners_user }}" + +- name: Register runners + ansible.builtin.include_tasks: register-runner.yml + loop: "{{ forgejo_runners_settings | dict2items }}" + loop_control: + label: "{{ item.key }}" + +- name: Create runners configuration + ansible.builtin.template: + src: docker-compose.yml.j2 + dest: "{{ forgejo_runners_config_dir }}/docker-compose.yml" + owner: "{{ forgejo_runners_user }}" + group: "{{ forgejo_runners_user }}" + mode: "0644" + +- name: Start runners service + community.docker.docker_compose_v2: + project_src: "{{ forgejo_runners_config_dir }}" + files: + - docker-compose.yml diff --git a/roles/forgejo_runners/tasks/register-runner.yml b/roles/forgejo_runners/tasks/register-runner.yml new file mode 100644 index 0000000..ed5b84f --- /dev/null +++ b/roles/forgejo_runners/tasks/register-runner.yml @@ -0,0 +1,39 @@ +--- +- name: Check variables + ansible.builtin.assert: + that: + - forgejo_runners_instance is defined + - forgejo_runners_version is defined + - forgejo_runners_config_dir is defined + - "'key' in item" + - "'value' in item" + +- name: Create runner subdirectory + ansible.builtin.file: + path: "{{ forgejo_runners_config_dir }}/{{ item.key }}" + state: directory + mode: "0755" + owner: "{{ forgejo_runners_user }}" + group: "{{ forgejo_runners_user }}" + +- name: Register runner + ansible.builtin.command: + cmd: >- + docker run + -v /var/run/docker.sock:/var/run/docker.sock + -v {{ forgejo_runners_config_dir }}/{{ item.key }}:/data + --rm + --user {{ ansible_facts.getent_passwd[forgejo_runners_user][1] }}:{{ ansible_facts.getent_passwd[forgejo_runners_user][2] }} + code.forgejo.org/forgejo/runner:{{ forgejo_runners_version }} + forgejo-runner register --no-interactive + --token {{ item.value.token }} + --name {{ item.key }} + --instance {{ forgejo_runners_instance }} + creates: "{{ forgejo_runners_config_dir }}/{{ item.key }}/.runner" + notify: Start runners + +- name: Create runner configuration + ansible.builtin.template: + src: config.yml.j2 + dest: "{{ forgejo_runners_config_dir }}/{{ item.key }}/config.yml" + notify: Restart runners diff --git a/roles/forgejo_runners/templates/config.yml.j2 b/roles/forgejo_runners/templates/config.yml.j2 new file mode 100644 index 0000000..39eb084 --- /dev/null +++ b/roles/forgejo_runners/templates/config.yml.j2 @@ -0,0 +1,44 @@ +{{ ansible_managed | comment }} +log: + level: info + job_level: info + +runner: + file: .runner + capacity: 1 + timeout: 3h + shutdown_timeout: 3h + insecure: false + fetch_timeout: 5s + fetch_interval: 2s + report_interval: 1s +{% if item.value.labels | default({}) %} + labels: +{% for label_name, label_value in item.value.labels.items() %} + - "{{ label_name }}:{{ label_value }}" +{% endfor %} +{% endif %} + +cache: + enabled: true + port: 0 + dir: "" + external_server: "" + secret: "" + host: "" + proxy_port: 0 + actions_cache_url_override: "" + +container: + network: "" + enable_ipv6: false + privileged: false + options: + workdir_parent: + valid_volumes: [] + docker_host: "-" + force_pull: false + force_rebuild: false + +host: + workdir_parent: diff --git a/roles/forgejo_runners/templates/docker-compose.yml.j2 b/roles/forgejo_runners/templates/docker-compose.yml.j2 new file mode 100644 index 0000000..3bf2eb6 --- /dev/null +++ b/roles/forgejo_runners/templates/docker-compose.yml.j2 @@ -0,0 +1,27 @@ +--- +{{ ansible_managed | comment }} +services: + docker: + image: docker:dind + privileged: true + restart: always + volumes: + - certs:/certs + +{% for runner in forgejo_runners_settings %} + runner-{{ runner }}: + image: code.forgejo.org/forgejo/runner:{{ forgejo_runners_version }} + user: {{ ansible_facts.getent_passwd[forgejo_runners_user][1] }}:{{ ansible_facts.getent_passwd[forgejo_runners_user][2] }} + environment: + DOCKER_HOST: tcp://docker:2376 + DOCKER_TLS_VERIFY: 1 + DOCKER_CERT_PATH: /certs/client + restart: always + volumes: + - {{ forgejo_runners_config_dir }}/{{ runner }}:/data + - certs:/certs + command: 'forgejo-runner --config config.yml daemon' +{% endfor %} + +volumes: + certs: diff --git a/roles/galene/README.md b/roles/galene/README.md new file mode 100644 index 0000000..5808875 --- /dev/null +++ b/roles/galene/README.md @@ -0,0 +1,213 @@ +# Ansible Role Galene + +Install and configure [Galene](https://galene.org) videoconference server. + +## Table of content + + +* [Role variables](#variables) + * [`galene_version`](#variable-galene_version) + * [`galene_http_port`](#variable-galene_http_port) + * [`galene_turn`](#variable-galene_turn) + * [`galene_user`](#variable-galene_user) + * [`galene_group`](#variable-galene_group) + * [`galene_base_directory`](#variable-galene_base_directory) + * [`galene_data_directory`](#variable-galene_data_directory) + * [`galene_groups_directory`](#variable-galene_groups_directory) + * [`galene_recording_directory`](#variable-galene_recording_directory) + * [`galene_static_directory`](#variable-galene_static_directory) + * [`galene_domain`](#variable-galene_domain) + * [`galene_config`](#variable-galene_config) + * [`galene_groups`](#variable-galene_groups) + + + +## Role variables + +The following variables can be configured for this role: + +| Variable | Type | Required | Default | Description (abstract) | +|----------|------|----------|---------|------------------------| +| `galene_version` | `str` | No | `"galene-1.0"` | Reference (branch or tag) of the Galene git repository. | +| `galene_http_port` | `int` | No | `443` | Port to listen. | +| `galene_turn` | `str` | No | `":1194"` | TURN address. | +| `galene_user` | `str` | No | `"galene"` | Operating system user to run the service. | +| `galene_group` | `str` | No | `"galene"` | Operating system group to run the service. | +| `galene_base_directory` | `path` | No | `"/var/lib/galene"` | Path to the base directory. | +| `galene_data_directory` | `path` | No | `"{{ galene_base_directory }}/data"` | Path to the data directory. | +| `galene_groups_directory` | `path` | No | `"{{ galene_base_directory }}/groups"` | Path to the groups directory. | +| `galene_recording_directory` | `path` | No | `"{{ galene_base_directory }}/recordings"` | Path to the recordings directory. | +| `galene_static_directory` | `path` | No | `"{{ galene_base_directory }}/static"` | Path to the static directory. | +| `galene_domain` | `str` | No | N/A | Domain name.

Used to generate TLS certificates. | +| `galene_config` | `dict` | No | N/A | Custom settings.

Key is the name of the setting.

Value is the value of the setting.

See [The global configuration file](https://galene.org/galene.html#the-global-configuration-file). | +| `galene_groups` | `dict` | No | N/A | Dict of groups.

Key is the group name.

Value is the group definition.

See [Group definitions](https://galene.org/galene.html#group-definitions). | + +### `galene_version` + +[*⇑ Back to ToC ⇑*](#toc) + +Reference (branch or tag) of the Galene git repository. + +- **Type**: `str` +- **Required**: No +- **Default**: `"galene-1.0"` + + + +### `galene_http_port` + +[*⇑ Back to ToC ⇑*](#toc) + +Port to listen. + +- **Type**: `int` +- **Required**: No +- **Default**: `443` + + + +### `galene_turn` + +[*⇑ Back to ToC ⇑*](#toc) + +TURN address. + +- **Type**: `str` +- **Required**: No +- **Default**: `":1194"` + + + +### `galene_user` + +[*⇑ Back to ToC ⇑*](#toc) + +Operating system user to run the service. + +- **Type**: `str` +- **Required**: No +- **Default**: `"galene"` + + + +### `galene_group` + +[*⇑ Back to ToC ⇑*](#toc) + +Operating system group to run the service. + +- **Type**: `str` +- **Required**: No +- **Default**: `"galene"` + + + +### `galene_base_directory` + +[*⇑ Back to ToC ⇑*](#toc) + +Path to the base directory. + +- **Type**: `path` +- **Required**: No +- **Default**: `"/var/lib/galene"` + + + +### `galene_data_directory` + +[*⇑ Back to ToC ⇑*](#toc) + +Path to the data directory. + +- **Type**: `path` +- **Required**: No +- **Default**: `"{{ galene_base_directory }}/data"` + + + +### `galene_groups_directory` + +[*⇑ Back to ToC ⇑*](#toc) + +Path to the groups directory. + +- **Type**: `path` +- **Required**: No +- **Default**: `"{{ galene_base_directory }}/groups"` + + + +### `galene_recording_directory` + +[*⇑ Back to ToC ⇑*](#toc) + +Path to the recordings directory. + +- **Type**: `path` +- **Required**: No +- **Default**: `"{{ galene_base_directory }}/recordings"` + + + +### `galene_static_directory` + +[*⇑ Back to ToC ⇑*](#toc) + +Path to the static directory. + +- **Type**: `path` +- **Required**: No +- **Default**: `"{{ galene_base_directory }}/static"` + + + +### `galene_domain` + +[*⇑ Back to ToC ⇑*](#toc) + +Domain name. + +Used to generate TLS certificates. + +- **Type**: `str` +- **Required**: No + + + +### `galene_config` + +[*⇑ Back to ToC ⇑*](#toc) + +Custom settings. + +Key is the name of the setting. + +Value is the value of the setting. + +See [The global configuration file](https://galene.org/galene.html#the-global-configuration-file). + +- **Type**: `dict` +- **Required**: No + + + +### `galene_groups` + +[*⇑ Back to ToC ⇑*](#toc) + +Dict of groups. + +Key is the group name. + +Value is the group definition. + +See [Group definitions](https://galene.org/galene.html#group-definitions). + +- **Type**: `dict` +- **Required**: No + + + + + diff --git a/roles/galene/defaults/main.yml b/roles/galene/defaults/main.yml new file mode 100644 index 0000000..7019a4a --- /dev/null +++ b/roles/galene/defaults/main.yml @@ -0,0 +1,95 @@ +--- + +# Reference (branch or tag) of the Galene git repository. +# +# - Type: str +# - Required: No +# - Default: galene-1.0 +galene_version: galene-1.0 + +# Port to listen. +# +# - Type: int +# - Required: No +# - Default: 443 +galene_http_port: 443 + +# TURN address. +# +# - Type: str +# - Required: No +# - Default: :1194 +galene_turn: ":1194" + +# Operating system user to run the service. +# +# - Type: str +# - Required: No +# - Default: galene +galene_user: galene + +# Operating system group to run the service. +# +# - Type: str +# - Required: No +# - Default: galene +galene_group: galene + +# Path to the base directory. +# +# - Type: path +# - Required: No +# - Default: /var/lib/galene +galene_base_directory: /var/lib/galene + +# Path to the data directory. +# +# - Type: path +# - Required: No +# - Default: {{ galene_base_directory }}/data +galene_data_directory: "{{ galene_base_directory }}/data" + +# Path to the groups directory. +# +# - Type: path +# - Required: No +# - Default: {{ galene_base_directory }}/groups +galene_groups_directory: "{{ galene_base_directory }}/groups" + +# Path to the recordings directory. +# +# - Type: path +# - Required: No +# - Default: {{ galene_base_directory }}/recordings +galene_recording_directory: "{{ galene_base_directory }}/recordings" + +# Path to the static directory. +# +# - Type: path +# - Required: No +# - Default: {{ galene_base_directory }}/static +galene_static_directory: "{{ galene_base_directory }}/static" + +# Custom settings. +# +# Key is the name of the setting. +# +# Value is the value of the setting. +# +# See . +# +# - Type: dict +# - Required: No +galene_config: {} + +# Dict of groups. +# +# Key is the group name. +# +# Value is the group definition. +# +# See . +# +# - Type: dict +# - Required: No +galene_groups: {} diff --git a/roles/galene/handlers/main.yml b/roles/galene/handlers/main.yml new file mode 100644 index 0000000..24198bf --- /dev/null +++ b/roles/galene/handlers/main.yml @@ -0,0 +1,9 @@ +--- +- name: Reload systemd + ansible.builtin.systemd_service: + daemon_reload: true + +- name: Restart galene + ansible.builtin.service: + name: galene + state: restarted diff --git a/roles/galene/meta/argument_specs.yml b/roles/galene/meta/argument_specs.yml new file mode 100644 index 0000000..aa3448c --- /dev/null +++ b/roles/galene/meta/argument_specs.yml @@ -0,0 +1,85 @@ +--- +argument_specs: + main: + short_description: Install and configure Galene videoconference server + description: + - Install and configure [Galene](https://galene.org/) videoconference server + author: + - jriou + options: + galene_version: + description: + - Reference (branch or tag) of the Galene git repository. + default: galene-1.0 + + galene_http_port: + description: + - Port to listen. + type: int + default: 443 + + galene_turn: + description: + - TURN address. + default: ":1194" + + galene_user: + description: + - Operating system user to run the service. + default: galene + + galene_group: + description: + - Operating system group to run the service. + default: galene + + galene_base_directory: + description: + - Path to the base directory. + type: path + default: /var/lib/galene + + galene_data_directory: + description: + - Path to the data directory. + type: path + default: "{{ galene_base_directory }}/data" + + galene_groups_directory: + description: + - Path to the groups directory. + type: path + default: "{{ galene_base_directory }}/groups" + + galene_recording_directory: + description: + - Path to the recordings directory. + type: path + default: "{{ galene_base_directory }}/recordings" + + galene_static_directory: + description: + - Path to the static directory. + type: path + default: "{{ galene_base_directory }}/static" + + galene_domain: + description: + - Domain name. + - Used to generate TLS certificates. + + galene_config: + description: + - Custom settings. + - Key is the name of the setting. + - Value is the value of the setting. + - See [The global configuration file](https://galene.org/galene.html#the-global-configuration-file). + type: dict + + galene_groups: + description: + - Dict of groups. + - Key is the group name. + - Value is the group definition. + - See [Group definitions](https://galene.org/galene.html#group-definitions). + type: dict diff --git a/roles/galene/meta/main.yml b/roles/galene/meta/main.yml new file mode 100644 index 0000000..affff51 --- /dev/null +++ b/roles/galene/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - role: golang diff --git a/roles/galene/molecule/default/converge.yml b/roles/galene/molecule/default/converge.yml new file mode 100644 index 0000000..bcc2b3b --- /dev/null +++ b/roles/galene/molecule/default/converge.yml @@ -0,0 +1,5 @@ +--- +- name: Converge + hosts: molecule + roles: + - galene diff --git a/roles/galene/molecule/default/create.yml b/roles/galene/molecule/default/create.yml new file mode 100644 index 0000000..6049019 --- /dev/null +++ b/roles/galene/molecule/default/create.yml @@ -0,0 +1,18 @@ +--- +- name: Create containers + hosts: localhost + gather_facts: false + tasks: + - name: Create containers + containers.podman.podman_container: + hostname: "{{ item }}" + name: "{{ item }}" + image: "{{ hostvars[item]['container_image'] }}" + state: started + loop: "{{ groups['molecule'] }}" + + - name: Wait for containers to be ready + ansible.builtin.wait_for_connection: + timeout: 300 + delegate_to: "{{ item }}" + loop: "{{ groups['molecule'] }}" diff --git a/roles/galene/molecule/default/destroy.yml b/roles/galene/molecule/default/destroy.yml new file mode 100644 index 0000000..b0596be --- /dev/null +++ b/roles/galene/molecule/default/destroy.yml @@ -0,0 +1,11 @@ +--- +- name: Destroy container instances + hosts: localhost + gather_facts: false + tasks: + - name: Remove containers + containers.podman.podman_container: + name: "{{ item }}" + state: absent + loop: "{{ groups['molecule'] }}" + failed_when: false diff --git a/roles/galene/molecule/default/inventory/hosts.yml b/roles/galene/molecule/default/inventory/hosts.yml new file mode 100644 index 0000000..f107edb --- /dev/null +++ b/roles/galene/molecule/default/inventory/hosts.yml @@ -0,0 +1,12 @@ +--- +molecule: + hosts: + debian11: + ansible_connection: containers.podman.podman + container_image: docker.io/geerlingguy/docker-debian11-ansible:latest + debian12: + ansible_connection: containers.podman.podman + container_image: docker.io/geerlingguy/docker-debian12-ansible:latest + debian13: + ansible_connection: containers.podman.podman + container_image: docker.io/geerlingguy/docker-debian13-ansible:latest diff --git a/roles/galene/molecule/default/molecule.yml b/roles/galene/molecule/default/molecule.yml new file mode 100644 index 0000000..af82e39 --- /dev/null +++ b/roles/galene/molecule/default/molecule.yml @@ -0,0 +1,26 @@ +--- +ansible: + executor: + args: + ansible_playbook: + - --inventory=inventory/ + env: + ANSIBLE_ROLES_PATH: ../../../../roles + playbooks: + create: create.yml + converge: converge.yml + verify: verify.yml + destroy: destroy.yml + +dependency: + name: galaxy + options: + requirements-file: ${MOLECULE_SCENARIO_DIRECTORY}/requirements.yml + +scenario: + test_sequence: + - create + - converge + - idempotence + - verify + - destroy diff --git a/roles/galene/molecule/default/requirements.yml b/roles/galene/molecule/default/requirements.yml new file mode 100644 index 0000000..25a97a4 --- /dev/null +++ b/roles/galene/molecule/default/requirements.yml @@ -0,0 +1,3 @@ +--- +collections: + - name: containers.podman diff --git a/roles/galene/molecule/default/verify.yml b/roles/galene/molecule/default/verify.yml new file mode 100644 index 0000000..fc4053c --- /dev/null +++ b/roles/galene/molecule/default/verify.yml @@ -0,0 +1,8 @@ +--- +- name: Verify + hosts: molecule + tasks: + - name: Check service + ansible.builtin.uri: + url: https://localhost:443 + validate_certs: false diff --git a/roles/galene/tasks/main.yml b/roles/galene/tasks/main.yml new file mode 100644 index 0000000..d619a99 --- /dev/null +++ b/roles/galene/tasks/main.yml @@ -0,0 +1,117 @@ +--- +# TODO: install in block +- name: Install requirements + ansible.builtin.apt: + name: git + update_cache: true + +- name: Clone source code + ansible.builtin.git: + repo: https://github.com/jech/galene + dest: /opt/galene + version: "{{ galene_version }}" + +- name: Compile + ansible.builtin.command: + chdir: /opt/galene + cmd: go build -ldflags='-s -w' + creates: /opt/galene/galene + environment: + CGO_ENABLED: "0" + PATH: /usr/local/go/bin + +- name: Install + ansible.builtin.copy: + remote_src: true + src: /opt/galene/galene + dest: /usr/local/bin/galene + owner: root + group: root + mode: "0755" +# TODO End of install in block + +- name: Create user + ansible.builtin.user: + name: "{{ galene_user }}" + system: true + password: '!' + home: "{{ galene_base_directory }}" + create_home: false + +- name: Create directories + ansible.builtin.file: + path: "{{ item }}" + state: directory + owner: "{{ galene_user }}" + group: "{{ galene_group }}" + mode: "0755" + loop: + - "{{ galene_base_directory }}" + - "{{ galene_data_directory }}" + - "{{ galene_groups_directory }}" + - "{{ galene_recording_directory }}" + - "{{ galene_static_directory }}" + +- name: Copy static directory + ansible.builtin.copy: + src: /opt/galene/static/ + dest: "{{ galene_static_directory }}/" + remote_src: true + mode: "0755" + owner: "{{ galene_user }}" + group: "{{ galene_group }}" + when: galene_static_directory != "/opt/galene/static" + +- name: Configure groups + ansible.builtin.copy: + content: "{{ item.value | to_json }}" + dest: "{{ galene_groups_directory }}/{{ item.key }}.json" + owner: "{{ galene_user }}" + group: "{{ galene_group }}" + mode: "0600" + loop: "{{ galene_groups | dict2items }}" + loop_control: + label: "{{ item.key }}" + notify: Restart galene + +- name: Create global configuration + ansible.builtin.copy: + content: "{{ galene_config | to_json }}" + dest: "{{ galene_data_directory }}/config.json" + owner: "{{ galene_user }}" + group: "{{ galene_group }}" + mode: "0600" + notify: Restart galene + +- name: Configure TLS certificates + when: galene_domain is defined + ansible.builtin.copy: + remote_src: true + src: "{{ item.src }}" + dest: "{{ item.dest }}" + owner: "{{ galene_user }}" + group: "{{ galene_group }}" + loop: + - src: "/etc/letsencrypt/live/{{ galene_domain }}/fullchain.pem" + dest: "{{ galene_data_directory }}/cert.pem" + mode: "0644" + - src: "/etc/letsencrypt/live/{{ galene_domain }}/privkey.pem" + dest: "{{ galene_data_directory }}/key.pem" + mode: "0600" + +- name: Create service + ansible.builtin.template: + src: galene.service.j2 + dest: /etc/systemd/system/galene.service + mode: "0644" + owner: root + group: root + notify: + - Reload systemd + - Restart galene + +- name: Start service + ansible.builtin.service: + name: galene + state: started + enabled: true diff --git a/roles/galene/templates/galene.service.j2 b/roles/galene/templates/galene.service.j2 new file mode 100644 index 0000000..5a90399 --- /dev/null +++ b/roles/galene/templates/galene.service.j2 @@ -0,0 +1,19 @@ +{{ ansible_managed | comment }} + +[Unit] +Description=Galene +After=network.target + +[Service] +Type=simple +WorkingDirectory={{ galene_base_directory }} +User={{ galene_user }} +Group={{ galene_group }} +{% if galene_http_port < 1024 %} +AmbientCapabilities=CAP_NET_BIND_SERVICE +{% endif %} +ExecStart=/usr/local/bin/galene -http :{{ galene_http_port }} -data {{ galene_data_directory }} -groups {{ galene_groups_directory }} -recordings {{ galene_recording_directory }} -static {{ galene_static_directory }} -turn "{{ galene_turn }}" +LimitNOFILE=65536 + +[Install] +WantedBy=multi-user.target diff --git a/roles/golang/README.md b/roles/golang/README.md new file mode 100644 index 0000000..05a4ea1 --- /dev/null +++ b/roles/golang/README.md @@ -0,0 +1,34 @@ +# Ansible Role Go + +Install [Go](https://go.dev/). + +## Table of content + + +* [Role variables](#variables) + * [`golang_version`](#variable-golang_version) + + + +## Role variables + +The following variables can be configured for this role: + +| Variable | Type | Required | Default | Description (abstract) | +|----------|------|----------|---------|------------------------| +| `golang_version` | `str` | No | `"1.25.4"` | Version to install. | + +### `golang_version` + +[*⇑ Back to ToC ⇑*](#toc) + +Version to install. + +- **Type**: `str` +- **Required**: No +- **Default**: `"1.25.4"` + + + + + diff --git a/roles/golang/defaults/main.yml b/roles/golang/defaults/main.yml new file mode 100644 index 0000000..b127ea8 --- /dev/null +++ b/roles/golang/defaults/main.yml @@ -0,0 +1,8 @@ +--- + +# Version to install. +# +# - Type: str +# - Required: No +# - Default: 1.25.4 +golang_version: 1.25.4 diff --git a/roles/golang/meta/argument_specs.yml b/roles/golang/meta/argument_specs.yml new file mode 100644 index 0000000..67efd49 --- /dev/null +++ b/roles/golang/meta/argument_specs.yml @@ -0,0 +1,13 @@ +--- +argument_specs: + main: + short_description: Install Go + description: + - Install [Go](https://go.dev/). + author: + - jriou + options: + golang_version: + description: + - Version to install. + default: 1.25.4 diff --git a/roles/golang/molecule/default/converge.yml b/roles/golang/molecule/default/converge.yml new file mode 100644 index 0000000..aec4e7b --- /dev/null +++ b/roles/golang/molecule/default/converge.yml @@ -0,0 +1,7 @@ +--- +- name: Converge + hosts: molecule + roles: + - golang + vars: + golang_version: 1.25.4 diff --git a/roles/golang/molecule/default/create.yml b/roles/golang/molecule/default/create.yml new file mode 100644 index 0000000..6049019 --- /dev/null +++ b/roles/golang/molecule/default/create.yml @@ -0,0 +1,18 @@ +--- +- name: Create containers + hosts: localhost + gather_facts: false + tasks: + - name: Create containers + containers.podman.podman_container: + hostname: "{{ item }}" + name: "{{ item }}" + image: "{{ hostvars[item]['container_image'] }}" + state: started + loop: "{{ groups['molecule'] }}" + + - name: Wait for containers to be ready + ansible.builtin.wait_for_connection: + timeout: 300 + delegate_to: "{{ item }}" + loop: "{{ groups['molecule'] }}" diff --git a/roles/golang/molecule/default/destroy.yml b/roles/golang/molecule/default/destroy.yml new file mode 100644 index 0000000..b0596be --- /dev/null +++ b/roles/golang/molecule/default/destroy.yml @@ -0,0 +1,11 @@ +--- +- name: Destroy container instances + hosts: localhost + gather_facts: false + tasks: + - name: Remove containers + containers.podman.podman_container: + name: "{{ item }}" + state: absent + loop: "{{ groups['molecule'] }}" + failed_when: false diff --git a/roles/golang/molecule/default/inventory/hosts.yml b/roles/golang/molecule/default/inventory/hosts.yml new file mode 100644 index 0000000..f107edb --- /dev/null +++ b/roles/golang/molecule/default/inventory/hosts.yml @@ -0,0 +1,12 @@ +--- +molecule: + hosts: + debian11: + ansible_connection: containers.podman.podman + container_image: docker.io/geerlingguy/docker-debian11-ansible:latest + debian12: + ansible_connection: containers.podman.podman + container_image: docker.io/geerlingguy/docker-debian12-ansible:latest + debian13: + ansible_connection: containers.podman.podman + container_image: docker.io/geerlingguy/docker-debian13-ansible:latest diff --git a/roles/golang/molecule/default/molecule.yml b/roles/golang/molecule/default/molecule.yml new file mode 100644 index 0000000..af82e39 --- /dev/null +++ b/roles/golang/molecule/default/molecule.yml @@ -0,0 +1,26 @@ +--- +ansible: + executor: + args: + ansible_playbook: + - --inventory=inventory/ + env: + ANSIBLE_ROLES_PATH: ../../../../roles + playbooks: + create: create.yml + converge: converge.yml + verify: verify.yml + destroy: destroy.yml + +dependency: + name: galaxy + options: + requirements-file: ${MOLECULE_SCENARIO_DIRECTORY}/requirements.yml + +scenario: + test_sequence: + - create + - converge + - idempotence + - verify + - destroy diff --git a/roles/golang/molecule/default/requirements.yml b/roles/golang/molecule/default/requirements.yml new file mode 100644 index 0000000..25a97a4 --- /dev/null +++ b/roles/golang/molecule/default/requirements.yml @@ -0,0 +1,3 @@ +--- +collections: + - name: containers.podman diff --git a/roles/golang/molecule/default/verify.yml b/roles/golang/molecule/default/verify.yml new file mode 100644 index 0000000..03642db --- /dev/null +++ b/roles/golang/molecule/default/verify.yml @@ -0,0 +1,15 @@ +--- +- name: Verify + hosts: molecule + vars: + golang_version: 1.25.4 + tasks: + - name: Get version + ansible.builtin.command: + cmd: /usr/local/go/bin/go version + register: golang_version_cmd + + - name: Compare versions + ansible.builtin.assert: + that: + - golang_version_cmd.stdout | regex_search('^go version go' + golang_version + ' linux/amd64') != "" diff --git a/roles/golang/tasks/main.yml b/roles/golang/tasks/main.yml new file mode 100644 index 0000000..6af3007 --- /dev/null +++ b/roles/golang/tasks/main.yml @@ -0,0 +1,7 @@ +--- +- name: Install + ansible.builtin.unarchive: + src: "https://go.dev/dl/go{{ golang_version }}.linux-amd64.tar.gz" + dest: /usr/local + remote_src: true + creates: /usr/local/go diff --git a/roles/navidrome/.gitignore b/roles/navidrome/.gitignore new file mode 100644 index 0000000..5ceb386 --- /dev/null +++ b/roles/navidrome/.gitignore @@ -0,0 +1 @@ +venv diff --git a/roles/navidrome/README.md b/roles/navidrome/README.md new file mode 100644 index 0000000..2114e26 --- /dev/null +++ b/roles/navidrome/README.md @@ -0,0 +1,205 @@ +# Ansible Role Navidrome + +Ansible role to manage a [Navidrome](https://github.com/navidrome/navidrome) instance. + +## Table of Content + + +* [Role variables](#variables) + * [`navidrome_version`](#variable-navidrome_version) + * [`navidrome_arch`](#variable-navidrome_arch) + * [`navidrome_user`](#variable-navidrome_user) + * [`navidrome_group`](#variable-navidrome_group) + * [`navidrome_music_folder`](#variable-navidrome_music_folder) + * [`navidrome_data_folder`](#variable-navidrome_data_folder) + * [`navidrome_cache_folder`](#variable-navidrome_cache_folder) + * [`navidrome_manage_iptables`](#variable-navidrome_manage_iptables) + * [`navidrome_allowed_sources`](#variable-navidrome_allowed_sources) + * [`navidrome_address`](#variable-navidrome_address) + * [`navidrome_port`](#variable-navidrome_port) + * [`navidrome_enable_insights_collector`](#variable-navidrome_enable_insights_collector) + * [`navidrome_base_url`](#variable-navidrome_base_url) + + + +## Role variables + +The following variables can be configured for this role: + +| Variable | Type | Required | Default | Description (abstract) | +|----------|------|----------|---------|------------------------| +| `navidrome_version` | `str` | No | `"0.54.5"` | Version of the debian package. | +| `navidrome_arch` | `str` | No | `"amd64"` | Architecture of the debian package. | +| `navidrome_user` | `str` | No | `"navidrome"` | Operating system user to run the service. | +| `navidrome_group` | `str` | No | `"navidrome"` | Operating system group to run the service. | +| `navidrome_music_folder` | `path` | No | `"/opt/navidrome/music"` | Path to the music folder. | +| `navidrome_data_folder` | `path` | No | `"/var/lib/navidrome"` | Path to the data directory. | +| `navidrome_cache_folder` | `path` | No | `"{{ navidrome_data_folder }}/cache"` | Path to the cache folder. | +| `navidrome_manage_iptables` | `bool` | No | `false` | Configure iptables rules | +| `navidrome_allowed_sources` | `list` | No | N/A | List of IP ranges to allow when `navidrome_manage_iptables` is enabled | +| `navidrome_address` | `str` | No | `"localhost"` | Address to listen. | +| `navidrome_port` | `int` | No | `4533` | Port to listen | +| `navidrome_enable_insights_collector` | `bool` | No | `false` | Enable the insights collector. | +| `navidrome_base_url` | `str` | No | N/A | Base URL of the web interface. | + +### `navidrome_version` + +[*⇑ Back to ToC ⇑*](#toc) + +Version of the debian package. + +- **Type**: `str` +- **Required**: No +- **Default**: `"0.54.5"` + + + +### `navidrome_arch` + +[*⇑ Back to ToC ⇑*](#toc) + +Architecture of the debian package. + +- **Type**: `str` +- **Required**: No +- **Default**: `"amd64"` + + + +### `navidrome_user` + +[*⇑ Back to ToC ⇑*](#toc) + +Operating system user to run the service. + +- **Type**: `str` +- **Required**: No +- **Default**: `"navidrome"` + + + +### `navidrome_group` + +[*⇑ Back to ToC ⇑*](#toc) + +Operating system group to run the service. + +- **Type**: `str` +- **Required**: No +- **Default**: `"navidrome"` + + + +### `navidrome_music_folder` + +[*⇑ Back to ToC ⇑*](#toc) + +Path to the music folder. + +- **Type**: `path` +- **Required**: No +- **Default**: `"/opt/navidrome/music"` + + + +### `navidrome_data_folder` + +[*⇑ Back to ToC ⇑*](#toc) + +Path to the data directory. + +- **Type**: `path` +- **Required**: No +- **Default**: `"/var/lib/navidrome"` + + + +### `navidrome_cache_folder` + +[*⇑ Back to ToC ⇑*](#toc) + +Path to the cache folder. + +- **Type**: `path` +- **Required**: No +- **Default**: `"{{ navidrome_data_folder }}/cache"` + + + +### `navidrome_manage_iptables` + +[*⇑ Back to ToC ⇑*](#toc) + +Configure iptables rules + +- **Type**: `bool` +- **Required**: No +- **Default**: `false` + + + +### `navidrome_allowed_sources` + +[*⇑ Back to ToC ⇑*](#toc) + +List of IP ranges to allow when `navidrome_manage_iptables` is enabled + +- **Type**: `list` +- **Required**: No + + + +### `navidrome_address` + +[*⇑ Back to ToC ⇑*](#toc) + +Address to listen. + +- **Type**: `str` +- **Required**: No +- **Default**: `"localhost"` + + + +### `navidrome_port` + +[*⇑ Back to ToC ⇑*](#toc) + +Port to listen + +- **Type**: `int` +- **Required**: No +- **Default**: `4533` + + + +### `navidrome_enable_insights_collector` + +[*⇑ Back to ToC ⇑*](#toc) + +Enable the insights collector. + +- **Type**: `bool` +- **Required**: No +- **Default**: `false` + + + +### `navidrome_base_url` + +[*⇑ Back to ToC ⇑*](#toc) + +Base URL of the web interface. + +- **Type**: `str` +- **Required**: No + + + + + + +## Donate + +As we all love FOSS, you should consider sponsoring the +[Navidrome](https://github.com/navidrome/navidrome) project. diff --git a/roles/navidrome/defaults/main.yml b/roles/navidrome/defaults/main.yml new file mode 100644 index 0000000..a30acb5 --- /dev/null +++ b/roles/navidrome/defaults/main.yml @@ -0,0 +1,84 @@ +--- + +# Version of the debian package. +# +# - Type: str +# - Required: No +# - Default: 0.54.5 +navidrome_version: 0.54.5 + +# Architecture of the debian package. +# +# - Type: str +# - Required: No +# - Default: amd64 +navidrome_arch: amd64 + +# Operating system user to run the service. +# +# - Type: str +# - Required: No +# - Default: navidrome +navidrome_user: navidrome + +# Operating system group to run the service. +# +# - Type: str +# - Required: No +# - Default: navidrome +navidrome_group: navidrome + +# Path to the music folder. +# +# - Type: path +# - Required: No +# - Default: /opt/navidrome/music +navidrome_music_folder: /opt/navidrome/music + +# Path to the data directory. +# +# - Type: path +# - Required: No +# - Default: /var/lib/navidrome +navidrome_data_folder: /var/lib/navidrome + +# Path to the cache folder. +# +# - Type: path +# - Required: No +# - Default: {{ navidrome_data_folder }}/cache +navidrome_cache_folder: "{{ navidrome_data_folder }}/cache" + +# Configure iptables rules +# +# - Type: bool +# - Required: No +# - Default: false +navidrome_manage_iptables: false + +# List of IP ranges to allow when `navidrome_manage_iptables` is enabled +# +# - Type: list +# - Required: No +navidrome_allowed_sources: [] + +# Address to listen. +# +# - Type: str +# - Required: No +# - Default: localhost +navidrome_address: localhost + +# Port to listen +# +# - Type: int +# - Required: No +# - Default: 4533 +navidrome_port: 4533 + +# Enable the insights collector. +# +# - Type: bool +# - Required: No +# - Default: false +navidrome_enable_insights_collector: false diff --git a/roles/navidrome/handlers/main.yml b/roles/navidrome/handlers/main.yml new file mode 100644 index 0000000..152799e --- /dev/null +++ b/roles/navidrome/handlers/main.yml @@ -0,0 +1,14 @@ +--- +- name: Reload systemd + ansible.builtin.systemd_service: + daemon_reload: true + +- name: Restart navidrome + ansible.builtin.service: + name: navidrome + state: restarted + +- name: Save iptables + ansible.builtin.command: + cmd: netfilter-persistent save + changed_when: true diff --git a/roles/navidrome/meta/argument_specs.yml b/roles/navidrome/meta/argument_specs.yml new file mode 100644 index 0000000..9c1146e --- /dev/null +++ b/roles/navidrome/meta/argument_specs.yml @@ -0,0 +1,78 @@ +--- +argument_specs: + main: + short_description: Install Navidrome. + description: + - Install [Navidrome](https://github.com/navidrome/navidrome). + author: + - jriou + options: + navidrome_version: + description: + - Version of the debian package. + default: 0.54.5 + + navidrome_arch: + description: + - Architecture of the debian package. + default: amd64 + + navidrome_user: + description: + - Operating system user to run the service. + default: navidrome + + navidrome_group: + description: + - Operating system group to run the service. + default: navidrome + + navidrome_music_folder: + description: + - Path to the music folder. + type: path + default: /opt/navidrome/music + + navidrome_data_folder: + description: + - Path to the data directory. + type: path + default: /var/lib/navidrome + + navidrome_cache_folder: + description: + - Path to the cache folder. + type: path + default: "{{ navidrome_data_folder }}/cache" + + navidrome_manage_iptables: + description: + - Configure iptables rules + type: bool + default: false + + navidrome_allowed_sources: + description: + - List of IP ranges to allow when `navidrome_manage_iptables` is enabled + type: list + + navidrome_address: + description: + - Address to listen. + default: localhost + + navidrome_port: + description: + - Port to listen + type: int + default: 4533 + + navidrome_enable_insights_collector: + description: + - Enable the insights collector. + type: bool + default: false + + navidrome_base_url: + description: + - Base URL of the web interface. diff --git a/roles/navidrome/tasks/main.yml b/roles/navidrome/tasks/main.yml new file mode 100644 index 0000000..d575f0e --- /dev/null +++ b/roles/navidrome/tasks/main.yml @@ -0,0 +1,62 @@ +--- +- name: Install package + ansible.builtin.apt: + deb: "https://github.com/navidrome/navidrome/releases/download/v{{ navidrome_version }}/navidrome_{{ navidrome_version }}_linux_{{ navidrome_arch }}.deb" + +- name: Create directories + ansible.builtin.file: + state: directory + path: "{{ item }}" + owner: "{{ navidrome_user }}" + group: "{{ navidrome_group }}" + mode: "0755" + loop: + - "{{ navidrome_music_folder }}" + - "{{ navidrome_data_folder }}" + - "{{ navidrome_cache_folder }}" + +- name: Create configuration file + ansible.builtin.template: + src: navidrome.toml.j2 + dest: /etc/navidrome/navidrome.toml + owner: "{{ navidrome_user }}" + group: "{{ navidrome_group }}" + mode: "0644" + notify: + - Restart navidrome + +- name: Create systemd override directory + ansible.builtin.file: + state: directory + path: /etc/systemd/system/navidrome.service.d + owner: root + group: root + mode: "0755" + +- name: Add systemd override + ansible.builtin.template: + src: override.conf.j2 + dest: /etc/systemd/system/navidrome.service.d/override.conf + owner: root + group: root + mode: "0755" + notify: + - Reload systemd + - Restart navidrome + +- name: Start service + ansible.builtin.service: + name: navidrome + state: started + +- name: Manage iptables + ansible.builtin.iptables: + chain: INPUT + protocol: tcp + source: "{{ item }}" + destination_port: "{{ navidrome_port }}" + jump: ACCEPT + comment: navidrome + loop: "{{ navidrome_allowed_sources }}" + notify: Save iptables + when: navidrome_manage_iptables diff --git a/roles/navidrome/templates/navidrome.toml.j2 b/roles/navidrome/templates/navidrome.toml.j2 new file mode 100644 index 0000000..2b6492b --- /dev/null +++ b/roles/navidrome/templates/navidrome.toml.j2 @@ -0,0 +1,10 @@ +{{ ansible_managed | comment }} +MusicFolder = "{{ navidrome_music_folder }}" +DataFolder = "{{ navidrome_data_folder }}" +CacheFolder = "{{ navidrome_cache_folder }}" +Address = "{{ navidrome_address }}" +Port = "{{ navidrome_port }}" +EnableInsightsCollector = "{{ navidrome_enable_insights_collector }}" +{% if navidrome_base_url is defined %} +BaseUrl = "{{ navidrome_base_url }}" +{% endif %} diff --git a/roles/navidrome/templates/override.conf.j2 b/roles/navidrome/templates/override.conf.j2 new file mode 100644 index 0000000..371ef28 --- /dev/null +++ b/roles/navidrome/templates/override.conf.j2 @@ -0,0 +1,5 @@ +{{ ansible_managed | comment }} +[Service] +User={{ navidrome_user }} +WorkingDirectory={{ navidrome_data_folder }} +ReadWritePaths={{ navidrome_data_folder }} diff --git a/test-requirements.txt b/test-requirements.txt new file mode 100644 index 0000000..4c8ddfb --- /dev/null +++ b/test-requirements.txt @@ -0,0 +1,2 @@ +ansible-core +molecule diff --git a/test-requirements.yml b/test-requirements.yml new file mode 100644 index 0000000..25a97a4 --- /dev/null +++ b/test-requirements.yml @@ -0,0 +1,3 @@ +--- +collections: + - name: containers.podman