diff --git a/roles/rclone_yandex/.ansible-lint b/roles/rclone_yandex/.ansible-lint new file mode 100644 index 0000000..f865478 --- /dev/null +++ b/roles/rclone_yandex/.ansible-lint @@ -0,0 +1,16 @@ +--- +profile: production +strict: true + +# Enable checking of loop variable prefixes in roles +loop_var_prefix: "^(__|{role}_)" + +skip_list: + - var-naming[no-role-prefix] + +warn_list: + - role-name[path] + - var-naming[no-role-prefix] + +exclude_paths: + - .github/ diff --git a/roles/rclone_yandex/.gitignore b/roles/rclone_yandex/.gitignore new file mode 100644 index 0000000..8cd0df3 --- /dev/null +++ b/roles/rclone_yandex/.gitignore @@ -0,0 +1,2 @@ +.vscode +.idea \ No newline at end of file diff --git a/roles/rclone_yandex/.yamllint b/roles/rclone_yandex/.yamllint new file mode 100644 index 0000000..611db54 --- /dev/null +++ b/roles/rclone_yandex/.yamllint @@ -0,0 +1,8 @@ +--- +rules: + brackets: + forbid: false + min-spaces-inside: 0 + max-spaces-inside: 2 + min-spaces-inside-empty: -1 + max-spaces-inside-empty: 2 diff --git a/roles/rclone_yandex/README.md b/roles/rclone_yandex/README.md new file mode 100644 index 0000000..8e6f453 --- /dev/null +++ b/roles/rclone_yandex/README.md @@ -0,0 +1,41 @@ +Role Name +========= + +A brief description of the role goes here. + +Requirements +------------ + +Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. + +Role Variables +-------------- + +`rclone_config_path`: where to keep the configuration file (default: `/root/rclone.conf`) +`rclone_mountpoint`: where to mount the Yandex Disk share +`rclone_group`: how to name the group that will own the mountpoint + +Dependencies +------------ + +A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. + +Example Playbook +---------------- + +```yaml +roles: + - role: rclone_yandex + rclone_mountpoint: /mnt/yandex-disk + rclone_group: yandex +``` + +License +------- + +BSD + +Author Information +------------------ + +corvus-migratorius@proton.me \ No newline at end of file diff --git a/roles/rclone_yandex/defaults/main.yml b/roles/rclone_yandex/defaults/main.yml new file mode 100644 index 0000000..ed97d53 --- /dev/null +++ b/roles/rclone_yandex/defaults/main.yml @@ -0,0 +1 @@ +--- diff --git a/roles/rclone_yandex/environment.ci.yml b/roles/rclone_yandex/environment.ci.yml new file mode 100644 index 0000000..1c6d7b1 --- /dev/null +++ b/roles/rclone_yandex/environment.ci.yml @@ -0,0 +1,11 @@ +--- +name: ansible-rclone-yandex +channels: + - conda-forge +dependencies: + - python~=3.12.0 + - pip>=22.2 + - actionlint + - pip: + - -r requirements.txt + - -r requirements.ci.txt diff --git a/roles/rclone_yandex/environment.yml b/roles/rclone_yandex/environment.yml new file mode 100644 index 0000000..b86b81f --- /dev/null +++ b/roles/rclone_yandex/environment.yml @@ -0,0 +1,9 @@ +--- +name: ansible-rclone-yandex +channels: + - conda-forge +dependencies: + - python~=3.12.0 + - pip>=22.2 + - pip: + - -r requirements.txt diff --git a/roles/rclone_yandex/handlers/main.yml b/roles/rclone_yandex/handlers/main.yml new file mode 100644 index 0000000..ed97d53 --- /dev/null +++ b/roles/rclone_yandex/handlers/main.yml @@ -0,0 +1 @@ +--- diff --git a/roles/rclone_yandex/meta/main.yml b/roles/rclone_yandex/meta/main.yml new file mode 100644 index 0000000..94fef93 --- /dev/null +++ b/roles/rclone_yandex/meta/main.yml @@ -0,0 +1,17 @@ +--- +galaxy_info: + role_name: "rclone_yandex" + namespace: genlab + author: "Alexander Gorelyshev" + company: "Genlab, LLC" + description: "Deploy rclone as a systemd unit and mount a Yandex Disk storage" + license: "GPL-2.0-or-later" + min_ansible_version: "2.1" + + platforms: + - name: "Ubuntu" + versions: [ "focal", "jammy" ] + + galaxy_tags: [ ] + +dependencies: [] diff --git a/roles/rclone_yandex/molecule/default/converge.yml b/roles/rclone_yandex/molecule/default/converge.yml new file mode 100644 index 0000000..afa49dd --- /dev/null +++ b/roles/rclone_yandex/molecule/default/converge.yml @@ -0,0 +1,19 @@ +--- +- name: Converge + hosts: all + + pre_tasks: + - name: "Install basic tools" + ansible.builtin.apt: + name: + - curl + update_cache: true + cache_valid_time: 3600 + autoremove: true + autoclean: true + + roles: + - role: genlab.rclone_yandex + rclone_mountpoint: /mnt/yandex-disk + rclone_group: yandex + rclone_secrets: secrets/token.yml diff --git a/roles/rclone_yandex/molecule/default/molecule.yml b/roles/rclone_yandex/molecule/default/molecule.yml new file mode 100644 index 0000000..fd2f06d --- /dev/null +++ b/roles/rclone_yandex/molecule/default/molecule.yml @@ -0,0 +1,27 @@ +--- +dependency: + name: galaxy + +driver: + name: docker + +platforms: + - name: ubuntu + image: geerlingguy/docker-${MOLECULE_DISTRO:-ubuntu2204}-ansible:latest + pre_build_image: true + command: ${MOLECULE_DOCKER_COMMAND:-""} + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:rw + cgroupns_mode: host + privileged: true + +provisioner: + name: ansible + +verifier: + name: ansible + +lint: | + set -e + yamllint . + ansible-lint . diff --git a/roles/rclone_yandex/molecule/default/secrets/token.yml b/roles/rclone_yandex/molecule/default/secrets/token.yml new file mode 100644 index 0000000..0b0550a --- /dev/null +++ b/roles/rclone_yandex/molecule/default/secrets/token.yml @@ -0,0 +1,5 @@ +rclone: + access_token: "y0_Axxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx..." + token_type: "OAuth" + refresh_token: "1:SPUlxxxxxxxxxxxxxxxxxxxxxxxx..." + expiry: "2024-05-16T05:26:26.319196346Z" diff --git a/roles/rclone_yandex/molecule/default/verify.yml b/roles/rclone_yandex/molecule/default/verify.yml new file mode 100644 index 0000000..4868f6d --- /dev/null +++ b/roles/rclone_yandex/molecule/default/verify.yml @@ -0,0 +1,18 @@ +--- +- name: Verify + hosts: all + gather_facts: false + any_errors_fatal: true + become: true + + tasks: + - name: "Gather facts about the service" + ansible.builtin.service_facts: + + - name: "Check if the `rclone-yandex` service is running" + ansible.builtin.assert: + that: + - "'rclone-yandex.service' in ansible_facts.services" + - "ansible_facts.services['rclone-yandex.service'].state == 'running'" + fail_msg: "the 'rclone-yandex' service is not running!" + success_msg: "the 'rclone-yandex' service is up and running" diff --git a/roles/rclone_yandex/renovate.json b/roles/rclone_yandex/renovate.json new file mode 100644 index 0000000..5db72dd --- /dev/null +++ b/roles/rclone_yandex/renovate.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:recommended" + ] +} diff --git a/roles/rclone_yandex/requirements.ci.txt b/roles/rclone_yandex/requirements.ci.txt new file mode 100644 index 0000000..f631d13 --- /dev/null +++ b/roles/rclone_yandex/requirements.ci.txt @@ -0,0 +1,6 @@ +ansible-lint +molecule~=24.9.0 +molecule-plugins[docker] +docker +requests==2.31.0 # pinned to the latest version not breaking Docker SDK +yamllint diff --git a/roles/rclone_yandex/requirements.txt b/roles/rclone_yandex/requirements.txt new file mode 100644 index 0000000..90d4055 --- /dev/null +++ b/roles/rclone_yandex/requirements.txt @@ -0,0 +1 @@ +ansible diff --git a/roles/rclone_yandex/requirements.yml b/roles/rclone_yandex/requirements.yml new file mode 100644 index 0000000..3d5f1cd --- /dev/null +++ b/roles/rclone_yandex/requirements.yml @@ -0,0 +1,3 @@ +# requirements file +--- +collections: [] diff --git a/roles/rclone_yandex/tasks/configure.yaml b/roles/rclone_yandex/tasks/configure.yaml new file mode 100644 index 0000000..c20f52c --- /dev/null +++ b/roles/rclone_yandex/tasks/configure.yaml @@ -0,0 +1,58 @@ +--- +- name: "Configure | create a group - '{{ rclone_group }}'" + ansible.builtin.group: + name: "{{ rclone_group }}" + state: present + +- name: "Configure | get GID for '{{ rclone_group }}'" + register: rclone_group_gid + changed_when: false + failed_when: not rclone_group_gid.stdout + ansible.builtin.shell: + cmd: 'set -o pipefail && getent group "{{ rclone_group }}" | cut -d: -f3' + executable: /bin/bash + +- name: "Configure | display rclone mount ownership group" + ansible.builtin.debug: + msg: "'{{ rclone_group }}' ({{ rclone_group_gid.stdout }})" + +- name: "Configure | set up directories" + loop: + - {path: "/tmp/rclone", group: "root"} + - {path: "/mnt/yandex-disk", group: "{{ rclone_group }}"} + ansible.builtin.file: + state: directory + path: "{{ item.path }}" + owner: root + group: "{{ item.group }}" + mode: "0770" + +- name: "Configure | create the [yandex] section" + ansible.builtin.lineinfile: + create: true + path: "{{ rclone_config_path }}" + line: "[yandex]" + mode: "0660" + +- name: "Configure | read in the YAMLified Yandex share credentials" + ansible.builtin.include_vars: + file: "{{ rclone_secrets }}" + +- name: "Configure | insert/update the section for the [yandex] share" + ansible.builtin.blockinfile: + path: "{{ rclone_config_path }}" + insertafter: "^[yandex]" + block: | + type = yandex + token = {{ rclone | to_json }} + +- name: "Configure | template a systemd service file" + ansible.builtin.template: + src: templates/rclone-yandex.service.j2 + dest: /lib/systemd/system/rclone-yandex.service + mode: "0660" + +# validate attribute doesn't seem to work here, unfortunately, so command to the rescue +- name: "Configure | validate the service file" + ansible.builtin.command: systemd-analyze verify rclone-yandex.service + changed_when: false diff --git a/roles/rclone_yandex/tasks/install.yaml b/roles/rclone_yandex/tasks/install.yaml new file mode 100644 index 0000000..b42ae25 --- /dev/null +++ b/roles/rclone_yandex/tasks/install.yaml @@ -0,0 +1,39 @@ +--- +- name: "Install | unzip (RHEL)" + ansible.builtin.dnf: + name: [ unzip ] + state: installed + when: ansible_os_family == 'RHEL' + +- name: "Install | unzip (Debian)" + ansible.builtin.apt: + update_cache: true + name: [ unzip ] + state: present + when: ansible_os_family == 'Debian' + +- name: "Install | rclone_yandex" + block: + - name: "Install | check if rclone binary is available in PATH" + changed_when: false + ansible.builtin.command: + cmd: "rclone --version" + rescue: + - name: "Install | fetch and install the rclone binary" # noqa: no-changed-when + register: result + failed_when: result.rc != 0 + ansible.builtin.shell: + cmd: "set -o pipefail && curl https://rclone.org/install.sh | sudo bash" + executable: /bin/bash + +- name: "Install | fuse (RHEL)" + ansible.builtin.dnf: + name: [ fuse ] + state: installed + when: ansible_os_family == 'RHEL' + +- name: "Install | fuse (Debian)" + ansible.builtin.apt: + name: [ fuse3 ] + state: present + when: ansible_os_family == 'Debian' diff --git a/roles/rclone_yandex/tasks/main.yml b/roles/rclone_yandex/tasks/main.yml new file mode 100644 index 0000000..5adbe57 --- /dev/null +++ b/roles/rclone_yandex/tasks/main.yml @@ -0,0 +1,11 @@ +# tasks file +--- + +- name: "Include installation tasks" + ansible.builtin.include_tasks: "install.yaml" + +- name: "Include configuration tasks" + ansible.builtin.include_tasks: "configure.yaml" + +- name: "Include run tasks" + ansible.builtin.include_tasks: "run.yaml" diff --git a/roles/rclone_yandex/tasks/run.yaml b/roles/rclone_yandex/tasks/run.yaml new file mode 100644 index 0000000..306b5ed --- /dev/null +++ b/roles/rclone_yandex/tasks/run.yaml @@ -0,0 +1,6 @@ +--- +- name: "Run | start the 'rclone-yandex' service" + ansible.builtin.systemd: + name: rclone-yandex + state: started + daemon_reload: true diff --git a/roles/rclone_yandex/templates/rclone-yandex.service.j2 b/roles/rclone_yandex/templates/rclone-yandex.service.j2 new file mode 100644 index 0000000..a4601d8 --- /dev/null +++ b/roles/rclone_yandex/templates/rclone-yandex.service.j2 @@ -0,0 +1,26 @@ +[Unit] +Description=rclone: Remote FUSE filesystem for cloud storage config %i +Documentation=man:rclone(1) +After=network-online.target +Wants=network-online.target + +[Service] +Type=notify +ExecStart= \ + /usr/bin/rclone mount \ + --gid={{ rclone_group_gid.stdout }} \ + --dir-perms=0770 \ + --file-perms=0660 \ + --umask=007 \ + --default-permissions \ + --allow-other \ + --config "{{ rclone_config_path }}" \ + --log-file="/tmp/rclone/yandex.log" \ + --log-level=INFO \ + --vfs-cache-mode=off \ + yandex: "{{ rclone_mountpoint }}" + +ExecStop=/bin/fusermount -u "{{ rclone_mountpoint }}" + +[Install] +WantedBy=default.target \ No newline at end of file diff --git a/roles/rclone_yandex/vars/main.yml b/roles/rclone_yandex/vars/main.yml new file mode 100644 index 0000000..d1baeea --- /dev/null +++ b/roles/rclone_yandex/vars/main.yml @@ -0,0 +1,4 @@ +--- +# vars file for rclone_yandex + +rclone_config_path: "/root/rclone.conf"