From 8c0f7269232ac936aea848bd5e1b5aa50b7919d1 Mon Sep 17 00:00:00 2001
From: Arthur BOUDREAULT <arthur@lydra.fr>
Date: Mon, 25 Jul 2022 16:00:04 +0200
Subject: [PATCH] feat: add Ansible role Restic to use S3 backups

---
 roles/ynh_backup/README-FR.md         | 68 ++++++++++++++++++++-------
 roles/ynh_backup/README.md            | 67 +++++++++++++++++++-------
 roles/ynh_backup/defaults/main.yml    | 13 +++--
 roles/ynh_backup/tasks/backup.yml     | 10 ++--
 roles/ynh_backup/tasks/borgbackup.yml | 50 ++++++++++----------
 roles/ynh_backup/tasks/main.yml       | 13 +++--
 roles/ynh_backup/tasks/restic.yml     | 39 +++++++++++++++
 roles/ynh_backup/vars/main.yml        |  1 +
 8 files changed, 188 insertions(+), 73 deletions(-)
 create mode 100644 roles/ynh_backup/tasks/restic.yml

diff --git a/roles/ynh_backup/README-FR.md b/roles/ynh_backup/README-FR.md
index 178a558..359edab 100644
--- a/roles/ynh_backup/README-FR.md
+++ b/roles/ynh_backup/README-FR.md
@@ -11,10 +11,11 @@ YunoHost doit déjà être installé sur votre serveur.
 ## Variables du rôle
 
 Les variables par défaut sont disponibles dans `default/main.yml` cependant il est possible de les surcharger selon vos besoins.
-Nous avons intégré deux systèmes de sauvegardes différents à ce rôle YunoHost :
+Nous avons intégré trois systèmes de sauvegardes différents à ce rôle YunoHost :
 
 - sauvegardes natives YunoHost en local
-- sauvegardes à distance avec un [depot BorgBackup](https://borgbackup.readthedocs.io/en/stable/)
+- sauvegardes à distance avec un [dépôt BorgBackup](https://borgbackup.readthedocs.io/en/stable/)
+- sauvegardes à distance avec un [dépôt Restic](https://restic.readthedocs.io/en/stable/)
 
 ### Sauvegardes natives YunoHost locales
 
@@ -22,16 +23,15 @@ Nous avons intégré deux systèmes de sauvegardes différents à ce rôle YunoH
 
 ```yml
 ynh_backup:
-  scheduled: True
-  directory: "/data/backup"
-  scheduled_hour: "*"
-  scheduled_minute: "*/30"
+  scheduled:         True
+  directory:         "/data/backup"
+  scheduled_hour:    "*"
+  scheduled_minute:  "*/30"
   scheduled_weekday: "*"
-  scheduled_month: "*"
-  system: True
-  apps: True
+  scheduled_month:   "*"
+  system:            True
+  apps:              True
   number_days_to_keep: "2"
-
 ```
 
 - `ynh_backup.scheduled` : active la fonctionnalité de sauvegarde des applications YunoHost en mettant la valeur à `True`.
@@ -48,18 +48,17 @@ ynh_backup:
 
 ```yml
 ynh_borg_backup_scheduled: True
-borg_source_directories:
-  - "/data/yunohost"
-borg_repository: "/data/backup/live"
+borg_source_directories:    "{{ ynh_backup.directory }}"
+borg_repository:            "/data/backup/live"
 borg_encryption_passphrase: "PLEASECHANGEME"
-borgmatic_config_name: "borgmatic_ynh_config"
-borgmatic_cron_name: "borgmatic_ynh_cron"
+borgmatic_config_name:      "borgmatic_ynh_config"
+borgmatic_cron_name:        "borgmatic_ynh_cron"
 borg_retention_policy:
   keep_daily: "4"
 ynh_borg_backup_remote_repo: True
-borg_ssh_keys_src: "files/prd/ssh_keys/ynh_ed25519.vault"
-borg_ssh_keys_dest: "/home/debian/.ssh/ynh_ed25519"
-ynh_ssh_borg_command: "ssh_command: ssh -p 7410 -o StrictHostKeychecking=no -i {{ borg_ssh_keys_dest }}"
+borg_ssh_keys_src:          "files/prd/ssh_keys/ynh_ed25519.vault"
+borg_ssh_keys_dest:         "/home/debian/.ssh/ynh_ed25519"
+ynh_ssh_borg_command:       "ssh_command: ssh -p 7410 -o StrictHostKeychecking=no -i {{ borg_ssh_keys_dest }}"
 ```
 
 - `ynh_borg_backup_scheduled` : Active / désactive la fonctionnalité de sauvegarde avec BorgBackup.
@@ -76,6 +75,39 @@ ynh_ssh_borg_command: "ssh_command: ssh -p 7410 -o StrictHostKeychecking=no -i {
 
 N'hésitez pas à regarder les variables disponibles dans le [rôle](https://github.com/borgbase/ansible-role-borgbackup).
 
+### Sauvegardes distantes avec Restic
+
+- Les sauvegardes avec [Restic](https://restic.net/) : Grâce au rôle Ansible `do1jlr.restic`, nous pouvons automatiser le processus d'installation et de configuration de Restic sur un serveur YunoHost. Les sauvegardes Borg Restic accessibles sur un dépôt Restic en local ou à distance et compatible stockage objet S3. Plus d'info sur ce rôle [ici](https://github.com/roles-ansible/ansible_role_restic).
+
+⚠️ Attention, pour pouvoir utiliser le rôle Ansible `do1jlr.restic`, vous devez avoir les paquets suivants installé sur la machine qui exécute Ansible : `bzip2` (binaire disponible sur la plupart des systèmes Linux) et `jmespath` (paquet python, installable avec pip).
+
+```yml
+
+restic_repos:
+  s3_ynh_restic_repo:
+    location:              "s3:s3.fr-par.scw.cloud/dummy_bucket_name"
+    password:              "dummy_restic_repo_password"
+    aws_access_key:        "dummy_access_key"
+    aws_secret_access_key: "dummy_secret_access_key"
+    aws_default_region:    "fr-par"
+    init: true
+
+restic_backups:
+  YunoHost_remote:
+    name:        "remote_ynh_restic"
+    repo:        "s3_ynh_restic_repo"
+    src:         "{{ ynh_backup.directory }}"
+    tags:
+      - yunohost
+      - remote
+    keep_within: "{{ restic_keep_time }}"
+    scheduled: true
+    schedule_hour: 1
+    schedule_minute: 0
+```
+
+N'hésitez pas à regarder les variables disponibles dans le [rôle](https://github.com/borgbase/ansible-role-borgbackup).
+
 ## Dépendances
 
 Le rôle `m3nu.ansible_role_borgbackup` sera installé sur la machine exécutant Ansible pour que les tâches liées à Borg fonctionnent. Un fichier `requirements.yml` est à la racine du rôle et va télécharger le rôle (par défaut vers `~/.ansible/roles`).
diff --git a/roles/ynh_backup/README.md b/roles/ynh_backup/README.md
index 59ba516..0521744 100644
--- a/roles/ynh_backup/README.md
+++ b/roles/ynh_backup/README.md
@@ -11,10 +11,11 @@ YunoHost needs to be installed on your server.
 ## Role Variables
 
 The default variables are available in `default/main.yml` however it is possible to override them according to your needs.
-We have integrated two different backup systems to this YunoHost role:
+We have integrated three different backup systems to this YunoHost role:
 
 - YunoHost native local backups
 - Remote backups with a [BorgBackup repository](https://borgbackup.readthedocs.io/en/stable/)
+- Remote backups with a [Restic repository](https://restic.readthedocs.io/en/stable/)
 
 ### YunoHost native local backups
 
@@ -22,16 +23,15 @@ YunoHost provides its own native backup system. It is able to back up YunoHost c
 
 ```yml
 ynh_backup:
-  scheduled: True
-  directory: "/data/backup"
-  scheduled_hour: "*"
-  scheduled_minute: "*/30"
+  scheduled:         True
+  directory:         "/data/backup"
+  scheduled_hour:    "*"
+  scheduled_minute:  "*/30"
   scheduled_weekday: "*"
-  scheduled_month: "*"
-  system: True
-  apps: True
-  src_script: "templates/ynh_backup.sh.j2"
-  dest_script: "/usr/bin"
+  scheduled_month:   "*"
+  system:            True
+  apps:              True
+  number_days_to_keep: "2"
 ```
 
 - `ynh_backup.scheduled`: Enable the YunoHost applications backup feature by setting the value to `True`.
@@ -48,22 +48,22 @@ ynh_backup:
 
 ```yml
 ynh_borg_backup_scheduled: True
-borg_source_directories:
-  - "/data/yunohost"
-borg_repository: "/data/backup/live"
+borg_source_directories:    "{{ ynh_backup.directory }}"
+borg_repository:            "/data/backup/live"
 borg_encryption_passphrase: "PLEASECHANGEME"
-borgmatic_config_name: "borgmatic_ynh_config"
-borgmatic_cron_name: "borgmatic_ynh_cron"
+borgmatic_config_name:      "borgmatic_ynh_config"
+borgmatic_cron_name:        "borgmatic_ynh_cron"
 borg_retention_policy:
   keep_daily: "4"
 ynh_borg_backup_remote_repo: True
-borg_ssh_keys_src: "files/prd/ssh_keys/ynh_ed25519.vault"
-borg_ssh_keys_dest: "/home/debian/.ssh/ynh_ed25519"
+borg_ssh_keys_src:          "files/prd/ssh_keys/ynh_ed25519.vault"
+borg_ssh_keys_dest:         "/home/debian/.ssh/ynh_ed25519"
+ynh_ssh_borg_command:       "ssh_command: ssh -p 7410 -o StrictHostKeychecking=no -i {{ borg_ssh_keys_dest }}"
 ```
 
 - `ynh_borg_backup_scheduled`: Enable / disable the backup feature with BorgBackup.
 - `ynh_borg_backup_remote_repo`: Enable / disable the backup functionality on a BorgBackup remote repository (tasks related to SSH keys setup). If you enable this feature, then you will need to use `borg_ssh_keys_src` and `borg_ssh_keys_dest` variables. 
-- `borg_source_directories`: List of source folders to back up. By default, this is the folder containing all YunoHost data (configuration, applications).
+- `borg_source_directories`: List of source folders to back up. By default, this is the folder in which YunoHost local backups are located.
 - `borg_repository`: Full path to the Borg repository. Possibility to give a list of repositories to save data in several places.
 - `borg_encryption_passphrase` : **Mandatory**, password to use for the Borg repository encryption key.
 - `borgmatic_config_name`: **Optional**, name of the Borgmatic configuration file.
@@ -75,6 +75,37 @@ borg_ssh_keys_dest: "/home/debian/.ssh/ynh_ed25519"
 
 Feel free to look at the variables available in the [role](https://github.com/borgbase/ansible-role-borgbackup).
 
+### remote backups with YunoHost Restic
+
+- Backups with [Restic](https://restic.net/): Thanks to the Ansible role `do1jlr.restic` we can automate the installation and configuration process of Restic on a YunoHost server. Restic backups are accessible on a local or a remote Restic repository and compatible with S3 object storage. More info about this role [here](https://github.com/roles-ansible/ansible_role_restic).
+
+```yml
+
+restic_repos:
+  s3_ynh_restic_repo:
+    location:              "s3:s3.fr-par.scw.cloud/dummy_bucket_name"
+    password:              "dummy_restic_repo_password"
+    aws_access_key:        "dummy_access_key"
+    aws_secret_access_key: "dummy_secret_access_key"
+    aws_default_region:    "fr-par"
+    init: true
+
+restic_backups:
+  YunoHost_remote:
+    name:        "remote_ynh_restic"
+    repo:        "s3_ynh_restic_repo"
+    src:         "{{ ynh_backup.directory }}"
+    tags:
+      - yunohost
+      - remote
+    keep_within: "{{ restic_keep_time }}"
+    scheduled: true
+    schedule_hour: 1
+    schedule_minute: 0
+```
+
+Feel free to look at the variables available in the [role](https://github.com/roles-ansible/ansible_role_restic).
+
 ## Dependencies
 
 The `m3nu.ansible_role_borgbackup` role will be installed on the machine running Ansible for Borg-related tasks to work. A `requirements.yml` file is in the root of the role and will download the role (by default to `~/.ansible/roles`).
diff --git a/roles/ynh_backup/defaults/main.yml b/roles/ynh_backup/defaults/main.yml
index 7b616ac..b68ee3b 100644
--- a/roles/ynh_backup/defaults/main.yml
+++ b/roles/ynh_backup/defaults/main.yml
@@ -23,10 +23,15 @@ ynh_backup:
   scheduled: False
 
 # Variables for YunoHost BorgBackup
-ynh_borg_backup_scheduled: False
+ynh_borg_backup_scheduled:   False
 borg_source_directories:
   - "/data/yunohost"
-borg_repository: "/data/backup/live"
-borg_init_command: "borgmatic init -c /etc/borgmatic/{{ borgmatic_config_name }} -e repokey --syslog-verbosity 1"
-borg_archive_name_format: "'{hostname}-yunohost-live-data-{now:%Y-%m-%d-%H%M%S}'"
+borg_repository:             "/data/backup/live"
+borg_init_command:           "borgmatic init -c /etc/borgmatic/{{ borgmatic_config_name }} -e repokey --syslog-verbosity 1"
+borg_archive_name_format:    "'{hostname}-yunohost-live-data-{now:%Y-%m-%d-%H%M%S}'"
 ynh_borg_backup_remote_repo: False
+
+# Variables for YunoHost Restic
+# https://github.com/roles-ansible/ansible_role_restic
+ynh_restic_backup_scheduled: False
+restic_schedule_type:        "cronjob"
diff --git a/roles/ynh_backup/tasks/backup.yml b/roles/ynh_backup/tasks/backup.yml
index 94ebd0b..7e6d6a3 100644
--- a/roles/ynh_backup/tasks/backup.yml
+++ b/roles/ynh_backup/tasks/backup.yml
@@ -25,19 +25,19 @@
 
 - name: Create backup folder if doesn't already exist
   ansible.builtin.file:
-    path: "{{ ynh_backup.directory }}"
+    path:  "{{ ynh_backup.directory }}"
     state: directory
-    mode: '0750'
+    mode:  '0750'
   when: ynh_backup.directory is defined
   tags: backup
 
 - name: Create backup script
   ansible.builtin.template:
-    src: "{{ ynh_backup_src_script }}"
-    dest: "{{ ynh_backup_dest_script }}"
+    src:   "{{ ynh_backup_src_script }}"
+    dest:  "{{ ynh_backup_dest_script }}"
     owner: root
     group: root
-    mode: '0740'
+    mode:  '0740'
   tags: backup
 
 - name: Create cron task to schedule YNH backup script
diff --git a/roles/ynh_backup/tasks/borgbackup.yml b/roles/ynh_backup/tasks/borgbackup.yml
index 9cb46ee..2dbfc28 100644
--- a/roles/ynh_backup/tasks/borgbackup.yml
+++ b/roles/ynh_backup/tasks/borgbackup.yml
@@ -18,12 +18,12 @@
 #                                                                             #
 #-----------------------------------------------------------------------------#
 - name: Download BorgBackup role on localhost
-  ansible.builtin.command: ansible-galaxy install m3nu.ansible_role_borgbackup,v0.9.0 -p ~/.ansible/roles
+  ansible.builtin.command: ansible-galaxy install m3nu.ansible_role_borgbackup,v0.9.0 -p "{{ _ansible_role_directory }}"
   delegate_to: localhost
   become: False
   tags:
-  - backup
-  - borg
+    - backup
+    - borg
 
 - name: Gather facts for BorgBackup role
   ansible.builtin.setup:
@@ -35,8 +35,8 @@
   ansible.builtin.import_role:
     name: m3nu.ansible_role_borgbackup
   tags:
-  - backup
-  - borg
+    - backup
+    - borg
 
 - name: Create backup folder for BorgBackup repository
   ansible.builtin.file:
@@ -44,29 +44,29 @@
     state: directory
     mode: '0750'
   tags:
-  - backup
-  - borg
+    - backup
+    - borg
 
 - name: Configure host for Borg Remote repository
   tags:
-  - backup
-  - borg
+    - backup
+    - borg
   block:
     - name: deploy ssh public key for BorgBackup
       ansible.builtin.copy:
-        src: "{{ borg_ssh_keys_src }}.pub"
-        dest: "{{ borg_ssh_keys_dest }}.pub"
+        src:   "{{ borg_ssh_keys_src }}.pub"
+        dest:  "{{ borg_ssh_keys_dest }}.pub"
         owner: "root"
         group: "root"
-        mode: 0600
+        mode:  0600
 
     - name: deploy ssh private key for BorgBackup
       ansible.builtin.copy:
-        src: "{{ borg_ssh_keys_src }}.vault"
-        dest: "{{ borg_ssh_keys_dest }}"
+        src:   "{{ borg_ssh_keys_src }}.vault"
+        dest:  "{{ borg_ssh_keys_dest }}"
         owner: "root"
         group: "root"
-        mode: 0600
+        mode:  0600
   when: ynh_borg_backup_remote_repo
 
 - name: change SSH command in "/etc/borgmatic/{{ borgmatic_config_name }}"
@@ -77,19 +77,19 @@
     state: present
   when: ynh_ssh_borg_command is defined
   tags:
-  - backup
-  - borg
+    - backup
+    - borg
 
 
 - name: change archive name in "/etc/borgmatic/{{ borgmatic_config_name }}"
   ansible.builtin.lineinfile:
-    path: "/etc/borgmatic/{{ borgmatic_config_name }}"
+    path:   "/etc/borgmatic/{{ borgmatic_config_name }}"
     regexp: "archive_name_format:"
     line: "    archive_name_format: {{ borg_archive_name_format }}"
     state: present
   tags:
-  - backup
-  - borg
+    - backup
+    - borg
 
 - name: Create borg launch script in /usr/local/bin
   ansible.builtin.copy:
@@ -97,16 +97,16 @@
       #!/bin/bash
       . /opt/borgmatic/bin/activate
       borg "$@"
-    dest: /usr/local/bin/borg
+    dest:  /usr/local/bin/borg
     owner: root
     group: root
     mode: "0755"
   tags:
-  - backup
-  - borg
+    - backup
+    - borg
 
 - name: Initialize a new Borg repository
   ansible.builtin.command: "{{ borg_init_command }}"
   tags:
-  - backup
-  - borg
+    - backup
+    - borg
diff --git a/roles/ynh_backup/tasks/main.yml b/roles/ynh_backup/tasks/main.yml
index ac16ba4..e932c65 100644
--- a/roles/ynh_backup/tasks/main.yml
+++ b/roles/ynh_backup/tasks/main.yml
@@ -23,9 +23,16 @@
   when: ynh_backup.scheduled
   tags: backup
 
-- name: Use Borg Backup with YunoHost
+- name: Use BorgBackup with YunoHost
   ansible.builtin.include_tasks: borgbackup.yml
   when: ynh_borg_backup_scheduled
   tags:
-  - backup
-  - borg
+    - backup
+    - borg
+
+- name: Use Restic with YunoHost
+  ansible.builtin.include_tasks: restic.yml
+  when: ynh_restic_backup_scheduled
+  tags:
+    - backup
+    - restic
diff --git a/roles/ynh_backup/tasks/restic.yml b/roles/ynh_backup/tasks/restic.yml
new file mode 100644
index 0000000..afe3722
--- /dev/null
+++ b/roles/ynh_backup/tasks/restic.yml
@@ -0,0 +1,39 @@
+---
+#-----------------------------------------------------------------------------#
+# ansible-yunohost allows to deploy Yunohost using Ansible                    #
+# Copyright 2021-present Lydra https://www.lydra.fr/                          #
+#                                                                             #
+# this program is free software: you can redistribute it and/or modify        #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# this program is distributed in the hope that it will be useful,             #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program. If not, see <http://www.gnu.org/licenses/>.        #
+#                                                                             #
+#-----------------------------------------------------------------------------#
+- name: Download Restic role on localhost
+  ansible.builtin.command: ansible-galaxy install do1jlr.restic,v0.7.1 -p "{{ _ansible_role_directory }}"
+  delegate_to: localhost
+  become:      False
+  tags:
+    - backup
+    - restic
+
+- name: Gather facts for Restic role
+  ansible.builtin.setup:
+  tags:
+    - backup
+    - restic
+
+- name: run Restic role
+  ansible.builtin.import_role:
+    name: do1jlr.restic
+  tags:
+    - backup
+    - restic
diff --git a/roles/ynh_backup/vars/main.yml b/roles/ynh_backup/vars/main.yml
index 2b41c9e..4b5fa40 100644
--- a/roles/ynh_backup/vars/main.yml
+++ b/roles/ynh_backup/vars/main.yml
@@ -22,3 +22,4 @@
 ynh_backup_src_script: "templates/ynh_backup.sh.j2"
 ynh_backup_dest_script: "/usr/local/bin/ynh_backup.sh"
 _ynh_backup_directory: "/home/yunohost.backup/archives"
+_ansible_role_directory: "~/.ansible/roles"
-- 
GitLab