From f418990e8498ea599475b5f9d39ecf803dc4264f Mon Sep 17 00:00:00 2001 From: Julien Riou Date: Mon, 23 Mar 2026 10:48:41 +0100 Subject: [PATCH] Initial commit Signed-off-by: Julien Riou --- .forgejo/workflows/ansible-ci.yml | 38 +++ .gitignore | 2 + README.md | 41 ++- galaxy.yml | 29 +++ roles/certbot/README.md | 77 ++++++ 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 | 232 +++++++++++++++++ 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 | 229 +++++++++++++++++ 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 | 50 ++++ 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 | 221 ++++++++++++++++ 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 + 85 files changed, 3520 insertions(+), 2 deletions(-) create mode 100644 .forgejo/workflows/ansible-ci.yml create mode 100644 .gitignore 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/README.md b/README.md index 450baf0..ca9e30a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,40 @@ -# ansible +# jriou.general -My Ansible collection \ No newline at end of file +My Ansible collection. + +## Releases + +See [Releases](https://git.riou.xyz/jriou/ansible/releases) for the available +versions. + +## Installation + +File `requirements.yml`: + +```yaml +collections: + - name: https://git.riou.xyz/jriou/ansible.git + type: git + version: 1.0.0 +``` + +Install with ansible-galaxy: + +``` +ansible-galaxy collection install -r requirements.yml +``` + +## Roles + +See the [roles](roles) directory for the complete list of roles and their +documentation. + +## Usage + +```yaml +- hosts: all + roles: + - jriou.general.role_name +``` + +Replace `role_name` with one of the available roles. 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..6533f36 --- /dev/null +++ b/roles/certbot/README.md @@ -0,0 +1,77 @@ +# 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` + + + + + + +## Usage + +Playbook example: + +```yaml +- hosts: all + roles: + - jriou.general.certbot +``` + +Then run the playbook: + +``` +ansible-playbook play.yml +``` 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..a825dcf --- /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 + +Playbook example: + +```yaml +- hosts: all + roles: + - jriou.general.coller +``` + +Then run the playbook: + +``` +ansible-playbook play.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..56c9205 --- /dev/null +++ b/roles/firefly/README.md @@ -0,0 +1,232 @@ +# 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 + +Playbook example: + +```yaml +- hosts: all + roles: + - jriou.general.firefly +``` + +Then run the playbook: + +``` +ansible-playbook play.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..b7bbed9 --- /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 + +Playbook example: + +```yaml +- hosts: all + roles: + - jriou.general.forgejo +``` + +Then run the playbook: + +``` +ansible-playbook play.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..33f9166 --- /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 + +Playbook example: + +```yaml +- hosts: all + roles: + - jriou.general.forgejo_runners + vars: + forgejo_runners_instance: https://codeberg.org # FIXME + forgejo_runners_settings: + my_runner: + token: **redacted** + labels: + node-latest: docker://data.forgejo.org/oci/node:latest +``` + +Then run the playbook: + +``` +ansible-playbook play.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..16b7104 --- /dev/null +++ b/roles/galene/README.md @@ -0,0 +1,229 @@ +# 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 + + + + + + +## Usage + +Playbook example: + +```yaml +- hosts: all + roles: + - jriou.general.galene +``` + +Then run the playbook: + +``` +ansible-playbook play.yml +``` 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..30e5eb5 --- /dev/null +++ b/roles/golang/README.md @@ -0,0 +1,50 @@ +# 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"` + + + + + + +## Usage + +Playbook example: + +```yaml +- hosts: all + roles: + - jriou.general.golang +``` + +Then run the playbook: + +``` +ansible-playbook play.yml +``` 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..24afac6 --- /dev/null +++ b/roles/navidrome/README.md @@ -0,0 +1,221 @@ +# 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 + + + + + + +## Usage + +Playbook example: + +```yaml +- hosts: all + roles: + - jriou.general.navidrome +``` + +Then run the playbook: + +``` +ansible-playbook play.yml +``` + +## 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