From 326038114aa1fe1d45f5385c2eb7d8dbf50f0654 Mon Sep 17 00:00:00 2001 From: Janik von Rotz Date: Sat, 10 Oct 2026 17:50:00 +0200 Subject: [PATCH] feat: move restic role to dedicated docker_restic role with S3 support and update documentation --- docs/roles.md | 3 +- logos/docker_restic.png | Bin 0 -> 61314 bytes prompt.md | 39 ++++++++++ roles/docker_restic/README.md | 42 ++++++++++ roles/docker_restic/defaults/main.yml | 9 +++ roles/docker_restic/meta/main.yml | 2 + roles/docker_restic/meta/vars.yml | 2 + .../tasks/docker_restic.yml} | 0 .../tasks/docker_restic_backup.yml} | 0 roles/docker_restic/tasks/main.yml | 12 +++ .../templates/docker-restic-backup | 0 .../templates/docker-restic-restore | 0 .../templates/restic-docker | 0 .../templates/restic.env | 0 roles/restic/README.md | 72 +++++------------- roles/restic/defaults/main.yml | 2 - roles/restic/tasks/main.yml | 6 ++ .../tasks/restic_docker_mariadb_backup.yml | 10 ++- .../tasks/restic_docker_mysql_backup.yml | 10 ++- .../tasks/restic_docker_odoo_backup.yml | 19 +++++ .../tasks/restic_docker_postgres_backup.yml | 10 ++- .../tasks/restic_docker_volume_backup.yml | 6 ++ roles/restic/tasks/restic_file_backup.yml | 8 +- roles/restic/tasks/restic_odoo_backup.yml | 17 +---- task | 25 +++--- 25 files changed, 199 insertions(+), 95 deletions(-) create mode 100644 logos/docker_restic.png create mode 100644 prompt.md create mode 100644 roles/docker_restic/README.md create mode 100644 roles/docker_restic/defaults/main.yml create mode 100644 roles/docker_restic/meta/main.yml create mode 100644 roles/docker_restic/meta/vars.yml rename roles/{restic/tasks/restic_s3.yml => docker_restic/tasks/docker_restic.yml} (100%) rename roles/{restic/tasks/restic_docker_restic_backup.yml => docker_restic/tasks/docker_restic_backup.yml} (100%) create mode 100644 roles/docker_restic/tasks/main.yml rename roles/{restic => docker_restic}/templates/docker-restic-backup (100%) rename roles/{restic => docker_restic}/templates/docker-restic-restore (100%) rename roles/{restic => docker_restic}/templates/restic-docker (100%) rename roles/{restic => docker_restic}/templates/restic.env (100%) create mode 100644 roles/restic/tasks/restic_docker_odoo_backup.yml diff --git a/docs/roles.md b/docs/roles.md index 4b3ce063..8116dd4b 100644 --- a/docs/roles.md +++ b/docs/roles.md @@ -28,6 +28,7 @@ | ![docker_hosts logo](/logos/docker_hosts.png) | [docker_hosts](roles/docker_hosts/README.md) | system | Docker hostname resolver. | | ![docker_network logo](/logos/docker_network.png) | [docker_network](roles/docker_network/README.md) | system | Configures a Docker network. | | ![docker logo](/logos/docker.png) | [docker](roles/docker/README.md) | system | Install Docker. | +| ![docker_restic logo](/logos/docker_restic.png) | [docker_restic](roles/docker_restic/README.md) | environment | Runs Restic in Docker container. | | ![docker_swarm logo](/logos/docker_swarm.png) | [docker_swarm](roles/docker_swarm/README.md) | system | Configures Docker Swarm. | | ![docker_volume logo](/logos/docker_volume.png) | [docker_volume](roles/docker_volume/README.md) | system | Configures a Docker volume. | | ![dozzle logo](/logos/dozzle.png) | [dozzle](roles/dozzle/README.md) | application | Deploy Dozzle container. | @@ -99,7 +100,7 @@ | ![remark42 logo](/logos/remark42.png) | [remark42](roles/remark42/README.md) | application | Deploy Remark42 container | | ![resolv logo](/logos/resolv.png) | [resolv](roles/resolv/README.md) | system | Manage DNS configuration. | | ![restic_exporter logo](/logos/restic_exporter.png) | [restic_exporter](roles/restic_exporter/README.md) | service | Add nginx config for Restic exporter path. | -| ![restic logo](/logos/restic.png) | [restic](roles/restic/README.md) | environment | Configures Restic backup jobs. | +| ![restic logo](/logos/restic.png) | [restic](roles/restic/README.md) | environment | Configure restic and backup jobs. | | ![restic_server logo](/logos/restic_server.png) | [restic_server](roles/restic_server/README.md) | service | Deploy Restic server container. | | ![s3cmd logo](/logos/s3cmd.png) | [s3cmd](roles/s3cmd/README.md) | environment | Install and configure s3cmd. | | ![simple_mail_forwarder logo](/logos/simple_mail_forwarder.png) | [simple_mail_forwarder](roles/simple_mail_forwarder/README.md) | service | Deploy Simple Mail Forwarder container. | diff --git a/logos/docker_restic.png b/logos/docker_restic.png new file mode 100644 index 0000000000000000000000000000000000000000..7c7cc0cb7b130ec89c7d7fbfd0ccfadc98fde770 GIT binary patch literal 61314 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 aE?*E1kJ9~^N3&fJfRBoTraV;EH1vNd-B&*V literal 0 HcmV?d00001 diff --git a/prompt.md b/prompt.md new file mode 100644 index 00000000..0ec08c36 --- /dev/null +++ b/prompt.md @@ -0,0 +1,39 @@ +--- +title: "Create task commands for logo scripts." +author: "Janik von Rotz " +state: draft +date_completed: YYYY-MM-DD +model: +input_tokens: +output_tokens: +--- + +# Create task commands for logo scripts. + +Note: @Clanker refers to the "ai agent" (you) who is working on this prompt file. + +@Clanker when working on this prompt file, make sure to: + +- Read context and task section first +- Prepare a list of todos +- Update the todo list while working on task + +## Context + +@Clanker Read the `AGENTS.md` and `README.md` to get an understanding of the project. + +## Task + +There are two scripts to update the logos `logos/resize-logos` and `logos/convert-logos`. + +I want you to create two new task commands from these scripts. + +Then remove the scripts. + +I will test the new commands by running `./task resize-logos` and `task convert-logos`. + +## Worklog + +@Clanker Add a summary here once the task has been completed. + +@Clanker Set frontmatter state to completed and update date and model. If you have access to session info also add token count. diff --git a/roles/docker_restic/README.md b/roles/docker_restic/README.md new file mode 100644 index 00000000..304b61cd --- /dev/null +++ b/roles/docker_restic/README.md @@ -0,0 +1,42 @@ +--- +kind: environment +--- + +docker_restic logo + + +# Docker Restic role + +Runs Restic in Docker container. + +## Usage + +Configure the role. + +```yml +# https://hub.docker.com/r/restic/restic +restic_image: restic/restic:0.19.1 +restic_owner: admin # default: root +restic_group: wheel # default: backup +restic_repo_type: s3 # default: s3 +restic_s3_endpoint: https://s3.swiss-backup02.infomaniak.com +restic_s3_bucket: my-restic-bucket +restic_s3_region: us-east-1 # default: us-east-1 +restic_s3_access_key: # default: "{{ vault_restic_s3_access_key }}" +restic_s3_secret_key: # default: "{{ vault_restic_s3_secret_key }}" +restic_backup_set: + +restic_backup_rotation: + daily: 7 # default: 7 + weekly: 4 # default: 4 + monthly: 1 # default: 1 +``` + +And include it in your playbook. + +```yml +- hosts: restic + roles: + - role: restic +``` + diff --git a/roles/docker_restic/defaults/main.yml b/roles/docker_restic/defaults/main.yml new file mode 100644 index 00000000..14fcfc8e --- /dev/null +++ b/roles/docker_restic/defaults/main.yml @@ -0,0 +1,9 @@ +--- +restic_repo_type: s3 +restic_s3_access_key: "{{ vault_restic_s3_access_key }}" +restic_s3_secret_key: "{{ vault_restic_s3_secret_key }}" +restic_backup_rotation: + last: 14 + daily: 14 + weekly: 4 + monthly: 3 diff --git a/roles/docker_restic/meta/main.yml b/roles/docker_restic/meta/main.yml new file mode 100644 index 00000000..23d65c7e --- /dev/null +++ b/roles/docker_restic/meta/main.yml @@ -0,0 +1,2 @@ +--- +dependencies: [] diff --git a/roles/docker_restic/meta/vars.yml b/roles/docker_restic/meta/vars.yml new file mode 100644 index 00000000..59afe586 --- /dev/null +++ b/roles/docker_restic/meta/vars.yml @@ -0,0 +1,2 @@ +--- +kind: environment diff --git a/roles/restic/tasks/restic_s3.yml b/roles/docker_restic/tasks/docker_restic.yml similarity index 100% rename from roles/restic/tasks/restic_s3.yml rename to roles/docker_restic/tasks/docker_restic.yml diff --git a/roles/restic/tasks/restic_docker_restic_backup.yml b/roles/docker_restic/tasks/docker_restic_backup.yml similarity index 100% rename from roles/restic/tasks/restic_docker_restic_backup.yml rename to roles/docker_restic/tasks/docker_restic_backup.yml diff --git a/roles/docker_restic/tasks/main.yml b/roles/docker_restic/tasks/main.yml new file mode 100644 index 00000000..c9194836 --- /dev/null +++ b/roles/docker_restic/tasks/main.yml @@ -0,0 +1,12 @@ +--- +- name: Include {{ role_name }} tasks + ansible.builtin.include_tasks: "{{ role_name }}.yml" + when: restic_repo_type is defined and restic_repo_type == 's3' + tags: + - restic + +- name: Include {{ role_name }} backup tasks + ansible.builtin.include_tasks: "{{ role_name }}_backup.yml" + when: restic_backup_set is defined + tags: + - restic diff --git a/roles/restic/templates/docker-restic-backup b/roles/docker_restic/templates/docker-restic-backup similarity index 100% rename from roles/restic/templates/docker-restic-backup rename to roles/docker_restic/templates/docker-restic-backup diff --git a/roles/restic/templates/docker-restic-restore b/roles/docker_restic/templates/docker-restic-restore similarity index 100% rename from roles/restic/templates/docker-restic-restore rename to roles/docker_restic/templates/docker-restic-restore diff --git a/roles/restic/templates/restic-docker b/roles/docker_restic/templates/restic-docker similarity index 100% rename from roles/restic/templates/restic-docker rename to roles/docker_restic/templates/restic-docker diff --git a/roles/restic/templates/restic.env b/roles/docker_restic/templates/restic.env similarity index 100% rename from roles/restic/templates/restic.env rename to roles/docker_restic/templates/restic.env diff --git a/roles/restic/README.md b/roles/restic/README.md index 50c37a40..769ee438 100644 --- a/roles/restic/README.md +++ b/roles/restic/README.md @@ -4,9 +4,10 @@ kind: environment restic logo + # Restic role -Configures Restic backup jobs. +Configure restic and backup jobs. ## Usage @@ -16,10 +17,10 @@ Configure the role. restic_backup_dir: /srv/backup # default: /var/backup restic_owner: admin # default: root restic_group: wheel # default: backup -restic_repo: "restic.example.com/{{ inventory_hostname }}" -restic_repo_password: # default: "{{ vault_restic_repo_password }}" restic_rest_user: rest-user # default: restic restic_rest_password: # default "{{ vault_restic_rest_password }}" +restic_repo: "restic.example.com/{{ inventory_hostname }}" +restic_repo_password: # default: "{{ vault_restic_repo_password }}" restic_backup_set: - id: "Backup Jenkins volume" @@ -42,7 +43,7 @@ restic_backup_set: hour: "1" - id: "Backup Bookstack files" - type: file + type: file-backup path: /usr/share/bookstack01 tags: - bookstack @@ -60,7 +61,7 @@ restic_backup_set: hour: "2" - id: "Backup Postgres database" - type: postgres-dump + type: docker-postgres-dump container: postgres01 databases: odoo tags: @@ -70,7 +71,7 @@ restic_backup_set: disabled: true - id: "Backup Postgres databases" - type: postgres-dump + type: docker-postgres-dump container: postgres01 tags: - postgres @@ -96,7 +97,7 @@ restic_backup_set: hour: "1" - id: "Backup MariaDB database" - type: mariadb-dump + type: docker-mariadb-dump container: mariadb01 databases: frappe tags: @@ -120,6 +121,18 @@ And include it in your playbook. ## Docs +### Backup types + +These backup types are available: + +* docker-mariadb-dump +* dokcer-mysql-dump +* docker-odoo-backup +* docker-postgres-dump +* docker-volume +* file-backup +* odoo-backup + ### Show restic version Show restic version for alls hosts. @@ -137,34 +150,6 @@ restic_repo_type: local # default: rest restic_repo: /home/backup ``` -### Setup an S3 repository - -Restic runs in a Docker container for S3 repositories. The credentials are -stored in `/etc/restic/restic.env` (`0600`, root only) and passed to the -container with `--env-file`. The wrapper script `/usr/local/bin/restic-docker` -contains no secrets. - -Set these vars: - -```yaml -# https://hub.docker.com/r/restic/restic -restic_image: restic/restic:0.19.1 -restic_repo_type: s3 # default: rest -restic_s3_endpoint: https://s3.swiss-backup02.infomaniak.com -restic_s3_bucket: my-restic-bucket -restic_s3_region: us-east-1 # default: us-east-1 -restic_s3_access_key: # default: "{{ vault_restic_s3_access_key }}" -restic_s3_secret_key: # default: "{{ vault_restic_s3_secret_key }}" -``` - -Store the secrets in the vault: - -```yaml -vault_restic_repo_password: "..." -vault_restic_s3_access_key: "..." -vault_restic_s3_secret_key: "..." -``` - ### Delete all snaphots Run these commands to remove all snapshots: @@ -174,21 +159,6 @@ restic forget --keep-last 1 --prune restic forget --prune latest ``` -### Backup types - -These backup types are available: - -* mariadb-dump -* mysql-dump -* postges-dump -* docker-volume -* docker-odoo-backup -* odoo-backup -* file -* docker-restic-backup - -## Docs - ### Change backup path The backup paths can be changed manually. Ensure that you have set `restic_backup_dir: /mnt/db/backup`. @@ -252,4 +222,4 @@ If your confident and did a test with a single host, run this command to replace ```bash task run all -i inventories/setup -b -m shell -a 'if [ -f /var/spool/cron/root ] && grep -q " restic " /var/spool/cron/root; then sed -i "s/ restic / restic-main /g" /var/spool/cron/root; fi; if [ -f /var/spool/cron/crontabs/root ] && grep -q " restic " /var/spool/cron/crontabs/root; then sed -i "s/ restic / restic-main /g" /var/spool/cron/crontabs/root; fi' -``` \ No newline at end of file +``` diff --git a/roles/restic/defaults/main.yml b/roles/restic/defaults/main.yml index 7606b1b5..29cfa2d7 100644 --- a/roles/restic/defaults/main.yml +++ b/roles/restic/defaults/main.yml @@ -6,8 +6,6 @@ restic_repo_type: rest restic_rest_user: restic restic_rest_password: "{{ vault_restic_rest_password }}" restic_repo_password: "{{ vault_restic_repo_password }}" -restic_s3_access_key: "{{ vault_restic_s3_access_key }}" -restic_s3_secret_key: "{{ vault_restic_s3_secret_key }}" restic_backup_rotation: last: 14 daily: 14 diff --git a/roles/restic/tasks/main.yml b/roles/restic/tasks/main.yml index b834411a..c832930a 100644 --- a/roles/restic/tasks/main.yml +++ b/roles/restic/tasks/main.yml @@ -29,6 +29,12 @@ tags: - restic +- name: Include {{ role_name }} docker odoo backup tasks + ansible.builtin.include_tasks: "{{ role_name }}_odoo_backup.yml" + when: restic_backup_set is defined + tags: + - restic + - name: Include {{ role_name }} docker postgres backup tasks ansible.builtin.include_tasks: "{{ role_name }}_docker_postgres_backup.yml" when: restic_backup_set is defined diff --git a/roles/restic/tasks/restic_docker_mariadb_backup.yml b/roles/restic/tasks/restic_docker_mariadb_backup.yml index 16b8210b..752464df 100644 --- a/roles/restic/tasks/restic_docker_mariadb_backup.yml +++ b/roles/restic/tasks/restic_docker_mariadb_backup.yml @@ -1,4 +1,10 @@ --- +- name: Verify docker-mysql-backup command exists + ansible.builtin.command: command -v docker-mysql-backup + changed_when: false + loop: "{{ restic_backup_set }}" + when: item.type == "docker-mysql-backup" + - name: Register selective docker mariadb backup jobs ansible.builtin.cron: name: "{{ item.id }}" @@ -9,7 +15,7 @@ disabled: "{{ item.disabled | default(false) }}" state: "{{ item.state | default('present') }}" loop: "{{ restic_backup_set }}" - when: item.type == "mariadb-dump" and item.databases is defined + when: item.type == "docker-mariadb-dump" and item.databases is defined - name: Register docker mariadb backup jobs ansible.builtin.cron: @@ -21,4 +27,4 @@ disabled: "{{ item.disabled | default(false) }}" state: "{{ item.state | default('present') }}" loop: "{{ restic_backup_set }}" - when: item.type == "mariadb-dump" and item.databases is undefined + when: item.type == "docker-mariadb-dump" and item.databases is undefined diff --git a/roles/restic/tasks/restic_docker_mysql_backup.yml b/roles/restic/tasks/restic_docker_mysql_backup.yml index ba8a071c..46b6141d 100644 --- a/roles/restic/tasks/restic_docker_mysql_backup.yml +++ b/roles/restic/tasks/restic_docker_mysql_backup.yml @@ -1,4 +1,10 @@ --- +- name: Verify docker-mysql-backup command exists + ansible.builtin.command: command -v docker-mysql-backup + changed_when: false + loop: "{{ restic_backup_set }}" + when: item.type == "docker-mysql-backup" + - name: Register selective docker mysql backup jobs ansible.builtin.cron: name: "{{ item.id }}" @@ -9,7 +15,7 @@ disabled: "{{ item.disabled | default(false) }}" state: "{{ item.state | default('present') }}" loop: "{{ restic_backup_set }}" - when: item.type == "mysql-dump" and item.databases is defined + when: item.type == "docker-mysql-dump" and item.databases is defined - name: Register docker mysql backup jobs ansible.builtin.cron: @@ -21,4 +27,4 @@ disabled: "{{ item.disabled | default(false) }}" state: "{{ item.state | default('present') }}" loop: "{{ restic_backup_set }}" - when: item.type == "mysql-dump" and item.databases is undefined + when: item.type == "docker-mysql-dump" and item.databases is undefined diff --git a/roles/restic/tasks/restic_docker_odoo_backup.yml b/roles/restic/tasks/restic_docker_odoo_backup.yml new file mode 100644 index 00000000..4909e801 --- /dev/null +++ b/roles/restic/tasks/restic_docker_odoo_backup.yml @@ -0,0 +1,19 @@ +--- +- name: Verify docker-odoo-backup command exists + ansible.builtin.command: command -v docker-odoo-backup + changed_when: false + loop: "{{ restic_backup_set }}" + when: item.type == "docker-odoo-backup" + +- name: Register odoo backup jobs + ansible.builtin.cron: + name: "{{ item.id }}" + hour: "{{ item.hour }}" + minute: "{{ 59 | random(seed=item.id) }}" + job: docker-odoo-backup -d {{ item.database }} -c {{ item.container }} -o {{ restic_backup_dir }} -f tar {{ '&& restic-main backup ' + restic_backup_dir + + '/' + item.database + '.tar --tag ' + (item.tags | join(' --tag ')) if item.upload | default(true) else '' }}; write-node-exporter-metric -c '{{ item.id + }}' -v $? + disabled: "{{ item.disabled | default(false) }}" + state: "{{ item.state | default('present') }}" + loop: "{{ restic_backup_set }}" + when: item.type == "docker-odoo-backup" diff --git a/roles/restic/tasks/restic_docker_postgres_backup.yml b/roles/restic/tasks/restic_docker_postgres_backup.yml index 63037b6b..cc0cf935 100644 --- a/roles/restic/tasks/restic_docker_postgres_backup.yml +++ b/roles/restic/tasks/restic_docker_postgres_backup.yml @@ -1,4 +1,10 @@ --- +- name: Verify docker-postgres-backup command exists + ansible.builtin.command: command -v docker-postgres-backup + changed_when: false + loop: "{{ restic_backup_set }}" + when: item.type == "docker-postgres-dump" + - name: Register selective docker postgres backup jobs ansible.builtin.cron: name: "{{ item.id }}" @@ -10,7 +16,7 @@ disabled: "{{ item.disabled | default(false) }}" state: "{{ item.state | default('present') }}" loop: "{{ restic_backup_set }}" - when: item.type == "postgres-dump" and item.databases is defined + when: item.type == "docker-postgres-dump" and item.databases is defined - name: Register docker postgres backup jobs ansible.builtin.cron: @@ -22,4 +28,4 @@ disabled: "{{ item.disabled | default(false) }}" state: "{{ item.state | default('present') }}" loop: "{{ restic_backup_set }}" - when: item.type == "postgres-dump" and item.databases is undefined + when: item.type == "docker-postgres-dump" and item.databases is undefined diff --git a/roles/restic/tasks/restic_docker_volume_backup.yml b/roles/restic/tasks/restic_docker_volume_backup.yml index a283c33e..b8e2de1a 100644 --- a/roles/restic/tasks/restic_docker_volume_backup.yml +++ b/roles/restic/tasks/restic_docker_volume_backup.yml @@ -1,4 +1,10 @@ --- +- name: Verify docker-volume-backup command exists + ansible.builtin.command: command -v docker-volume-backup + changed_when: false + loop: "{{ restic_backup_set }}" + when: item.type == "docker-volume" + - name: Register docker multi volume backup jobs ansible.builtin.cron: name: "{{ item.id }}" diff --git a/roles/restic/tasks/restic_file_backup.yml b/roles/restic/tasks/restic_file_backup.yml index fcf9e047..128d4708 100644 --- a/roles/restic/tasks/restic_file_backup.yml +++ b/roles/restic/tasks/restic_file_backup.yml @@ -1,10 +1,4 @@ --- -- name: Verify file path exists - ansible.builtin.command: ls {{ item.path }} - changed_when: false - loop: "{{ restic_backup_set }}" - when: item.type == "file" - - name: Register file backup jobs ansible.builtin.cron: name: "{{ item.id }}" @@ -15,4 +9,4 @@ disabled: "{{ item.disabled | default(false) }}" state: "{{ item.state | default('present') }}" loop: "{{ restic_backup_set }}" - when: item.type == "file" + when: item.type == "file-backup" diff --git a/roles/restic/tasks/restic_odoo_backup.yml b/roles/restic/tasks/restic_odoo_backup.yml index 2a260730..4ed9b455 100644 --- a/roles/restic/tasks/restic_odoo_backup.yml +++ b/roles/restic/tasks/restic_odoo_backup.yml @@ -1,6 +1,6 @@ --- -- name: Verify odoo backup command exists - ansible.builtin.shell: ls $(which odoo-backup) +- name: Verify odoo-backup command exists + ansible.builtin.command: command -v odoo-backup changed_when: false loop: "{{ restic_backup_set }}" when: item.type == "odoo-backup" @@ -17,16 +17,3 @@ state: "{{ item.state | default('present') }}" loop: "{{ restic_backup_set }}" when: item.type == "odoo-backup" - -- name: Register odoo backup jobs - ansible.builtin.cron: - name: "{{ item.id }}" - hour: "{{ item.hour }}" - minute: "{{ 59 | random(seed=item.id) }}" - job: docker-odoo-backup -d {{ item.database }} -c {{ item.container }} -o {{ restic_backup_dir }} -f tar {{ '&& restic-main backup ' + restic_backup_dir + - '/' + item.database + '.tar --tag ' + (item.tags | join(' --tag ')) if item.upload | default(true) else '' }}; write-node-exporter-metric -c '{{ item.id - }}' -v $? - disabled: "{{ item.disabled | default(false) }}" - state: "{{ item.state | default('present') }}" - loop: "{{ restic_backup_set }}" - when: item.type == "docker-odoo-backup" diff --git a/task b/task index 79216569..b736507e 100755 --- a/task +++ b/task @@ -25,13 +25,13 @@ help-table() { rows+=("===DOCS===| | ") rows+=("build-vuepress||Create vuepress build.") rows+=("dev-vuepress||Start vuepress development server.") - rows+=("docs||Update docs.") + rows+=("update-docs||Update docs.") rows+=("install-vuepress||Install build dependencies.") rows+=("serve-vuepress||Serve vuepress build.") - rows+=("update-roles-doc||Update readme files in roles folder.") + rows+=("format-role-readmes||Update readme files in roles folder.") rows+=("===LLM===| | ") rows+=("commit-with-llm||Commit with llm generated commit message.") - rows+=("update-with-llm|[glob][prompt]|Feed files matching glob with prompt to LLM and apply file changes.") + rows+=("update-with-llm|[glob][prompt]|Feed files matching and prompt to LLM and apply file changes.") rows+=("===DOCKER===| | ") rows+=("login-docker|[user][token]|Run Docker login and create docker config.") rows+=("===VAULT===| | ") @@ -41,7 +41,7 @@ help-table() { rows+=("encrypt-string|[vault_id] [key] [value] -q|Generate encrypted string with Ansible Vault.") rows+=("generate-encrypted-string|[vault_id] [key] -q|Generate encrypted string for key with Ansible Vault.") rows+=("generate-vault-password|[vault_id] [password]|Generate a password file for Ansible Vault.") - rows+=("show-vault-file|[vault_id] [path]|Show content of encrypted strings or fully encrypted vault file.") + rows+=("show-vault-file|[vault_id] [path]|Show content of encrypted strings or encrypted vault file.") rows+=("===SETUP===| | ") rows+=("install||Install Ansible and dependencies with uv.") rows+=("install-ansible-build-scripts|[role]|Install scripts of the specified Ansbile role.") @@ -67,7 +67,7 @@ help-table() { rows+=("upgrade-odoo|[env][step]|Run the Odoo upgrade for a target environment.") rows+=("===TEST===| | ") rows+=("test-project|[cleanup]|Deploy to localhost. Pass option 'cleanup' to reset test env.") - rows+=("test-scripts|[cleanup]|Install and test scripts. Pass option 'cleanup' to reset test env.") + rows+=("test-scripts|[cleanup]|Install and test scripts. Pass option 'cleanup' to reset env.") for row in "${rows[@]}"; do IFS='|' read -r cmd opt desc <<< "$row" @@ -747,12 +747,12 @@ test-scripts() { # Docs -docs() { +update-docs() { echo "Update roles.md" - echo "# Roles" > "roles.md" - echo "" >> "roles.md" - echo "| Logo | Role | Kind | Description |" >> "roles.md" - echo "| --- | --- | --- | --- |" >> "roles.md" + echo "# Roles" > "docs/roles.md" + echo "" >> "docs/roles.md" + echo "| Logo | Role | Kind | Description |" >> "docs/roles.md" + echo "| --- | --- | --- | --- |" >> "docs/roles.md" local md_files=$(find roles -name 'README.md' | sort) for readme in $md_files; do @@ -762,11 +762,11 @@ docs() { kind=$(grep "^kind:" "$readme" | sed 's/kind: //') local description description=$(sed -n '5,$p' "$readme" | grep -v '^$' | grep -v '> "roles.md" + echo "| ![$role logo](/logos/$role.png) | [$role]($readme) | $kind | $description |" >> "docs/roles.md" done } -update-roles-doc() { +format-role-readmes() { local md_files=$(find roles -name 'README.md' | sort) for readme in $md_files; do local role @@ -850,7 +850,6 @@ build-vuepress() { cp -r roles/nginx/files/* .vuepress/dist/nginx cp -r roles/odoo/files/* .vuepress/dist/odoo cp -r roles/postgres/files/* .vuepress/dist/postgres - } serve-vuepress() {