chore: ansible-lint

This commit is contained in:
Clément Désiles 2025-11-02 21:18:15 +01:00
parent 2c6da106b2
commit 2c421611ae
No known key found for this signature in database
53 changed files with 390 additions and 350 deletions

3
.ansible-lint Normal file
View File

@ -0,0 +1,3 @@
---
skip_list:
- var-naming[no-role-prefix]

View File

@ -1,13 +1,27 @@
# Homelab Ansible Playbooks # Homelab Ansible Playbooks
This repository contains Ansible playbooks and roles I use to manage my NAS and several VMs 👨‍💻. This repository contains Ansible playbooks and roles I use to manage my NAS and some VMs 👨‍💻.
This project is designed for personal/familial scale maintenance, if you find this useful for your use, want to share advises or security concerns, feel free to drop me a line. This project is designed for personal/familial scale maintenance, if you find this useful for your use, want to share advises or security concerns, feel free to drop me a line.
This is a good playground to learn and I encourage you to adapt these roles to your needs. While they might not be production-ready for all environments, I'm open to adapting them for [Ansible Galaxy]((https://galaxy.ansible.com)) if there's community interest! This is a good playground to learn and I encourage you to adapt these roles to your needs. While they might not be production-ready for all environments, I'm open to adapting them for [Ansible Galaxy](<(https://galaxy.ansible.com)>) if there's community interest!
## Requirements ## Requirements
Base tools:
```sh
# linux
apt-get install ansible ansible-lint ansible-galaxy
pacman -Syu ansible ansible-lint ansible-galaxy
# macos
brew install ansible ansible-lint ansible-galaxy
# windows
choco install ansible ansible-lint ansible-galaxy
```
Other roles:
```sh ```sh
ansible-galaxy collection install -r requirements.yml ansible-galaxy collection install -r requirements.yml
``` ```
@ -36,5 +50,6 @@ ssh-copy-id -i ~/.ssh/id_rsa.pub username@remote_host
Linting: Linting:
```sh ```sh
ansible-lint
npx prettier --write . npx prettier --write .
``` ```

View File

@ -1,5 +1,6 @@
[defaults] [defaults]
interpreter_python=/usr/bin/python3 interpreter_python=/usr/bin/python3
roles_path=./roles
[ssh_connection] [ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o ControlPath=/tmp/ansible-ssh-%h-%p-%r ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o ControlPath=/tmp/ansible-ssh-%h-%p-%r

View File

@ -1,3 +1,4 @@
---
# Network configuration # Network configuration
# --------------------- # ---------------------
network_interfaces: network_interfaces:

View File

@ -1,10 +1,16 @@
- hosts: all ---
# - hosts: all
# become: true
# roles:
# - role: networking
# - role: sshd
# - role: disks
# - role: wireguard
# - role: zsh
# - role: archlinux
# - role: podman
- hosts: pinwheel
become: true become: true
roles: roles:
- role: networking
- role: sshd - role: sshd
- role: disks
- role: wireguard
- role: zsh
- role: archlinux
- role: podman

View File

@ -1,3 +1,4 @@
---
- hosts: marge - hosts: marge
become: true become: true
roles: roles:

View File

@ -1,3 +1,4 @@
---
collections: collections:
- name: ansible.netcommon - name: ansible.netcommon
- name: community.general - name: community.general

View File

@ -0,0 +1,7 @@
Le classique quand on n'a pas mis à jour arch depuis un moment c'est d'avoir une clef PGP manquante.
```
sudo pacman -Sy archlinux-keyring
```
Avant l'update soigne les petits chats blessés.

View File

@ -1,3 +1,4 @@
---
arch_locale: en_US.UTF-8 arch_locale: en_US.UTF-8
yay_src_path: /opt/yay yay_src_path: /opt/yay
yay_git_repo: https://aur.archlinux.org/yay.git yay_git_repo: https://aur.archlinux.org/yay.git

View File

@ -1,15 +1,15 @@
--- ---
- name: Configure locales - name: Configure locales
block: block:
- name: activate locale - name: Activate locale
command: ansible.builtin.command:
cmd: localectl set-locale LANG={{ arch_locale }} cmd: localectl set-locale LANG={{ arch_locale }}
- name: edit /etc/locale.gen - name: Edit /etc/locale.gen
lineinfile: ansible.builtin.lineinfile:
dest: /etc/locale.gen dest: /etc/locale.gen
state: present state: present
regexp: "{{ arch_locale }}" regexp: "{{ arch_locale }}"
line: "{{ arch_locale }} UTF-8" line: "{{ arch_locale }} UTF-8"
- name: regenerate locales - name: Regenerate locales
command: ansible.builtin.command:
cmd: locale-gen cmd: locale-gen

View File

@ -1,10 +1,10 @@
--- ---
- name: Skip Archlinux installation - name: Skip Archlinux installation
meta: end_play ansible.builtin.meta: end_play
when: ansible_facts['os_family'] != 'Archlinux' when: ansible_facts['os_family'] != 'Archlinux'
- name: Archlinux base setup - name: Archlinux base setup
include_tasks: "{{ item }}" ansible.builtin.include_tasks: "{{ item }}"
loop: loop:
- pacman.yml - pacman.yml
- locales.yml - locales.yml

View File

@ -1,6 +1,6 @@
--- ---
- name: Check if pacman is not locked - name: Check if pacman is not locked
stat: ansible.builtin.stat:
path: /var/lib/pacman/db.lck path: /var/lib/pacman/db.lck
register: pacman_lock register: pacman_lock
failed_when: pacman_lock.stat.exists failed_when: pacman_lock.stat.exists
@ -13,32 +13,30 @@
# state: absent # state: absent
- name: Install reflector (looking for fastest mirror) - name: Install reflector (looking for fastest mirror)
pacman: community.general.pacman:
name: reflector name: reflector
state: present state: present
- name: Stat pacman mirrorlist - name: Stat pacman mirrorlist
stat: ansible.builtin.stat:
path: /etc/pacman.d/mirrorlist path: /etc/pacman.d/mirrorlist
register: mirrorlist register: mirrorlist
# Probably not here if it's a fresh install # Probably not here if it's a fresh install
- name: Stat pacman mirrorlist.bak - name: Stat pacman mirrorlist.bak
stat: ansible.builtin.stat:
path: /etc/pacman.d/mirrorlist.bak path: /etc/pacman.d/mirrorlist.bak
register: mirrorlist_bak register: mirrorlist_bak
- name: Backup and update pacman mirrorlist if older than 7 days - name: Backup and update pacman mirrorlist if older than 7 days
shell: > ansible.builtin.shell: >
cp /etc/pacman.d/mirrorlist /etc/pacman.d/mirrorlist.bak && cp /etc/pacman.d/mirrorlist /etc/pacman.d/mirrorlist.bak &&
reflector --latest 20 --protocol https --sort rate reflector --latest 20 --protocol https --sort rate
--save /etc/pacman.d/mirrorlist --save /etc/pacman.d/mirrorlist
when: mirrorlist_bak.stat.exists is false or when: mirrorlist_bak.stat.exists is false or (mirrorlist.stat.exists and (ansible_date_time.epoch | int - mirrorlist.stat.mtime) > 604800)
(mirrorlist.stat.exists and
(ansible_date_time.epoch | int - mirrorlist.stat.mtime) > 604800)
- name: Configure pacman to output colors - name: Configure pacman to output colors
lineinfile: ansible.builtin.lineinfile:
dest: /etc/pacman.conf dest: /etc/pacman.conf
state: present state: present
regexp: "^(.*)Color" regexp: "^(.*)Color"

View File

@ -1,10 +1,68 @@
--- ---
- name: Check if paru is already installed - name: Check if paru is already installed
stat: ansible.builtin.stat:
path: /usr/bin/paru path: /usr/bin/paru
register: paru register: paru
- name: Install paru - name: Install paru
when: not paru.stat.exists
##
## Deprecated version with compilation
##
# - name: Install paru
# block:
# - name: Install build dependencies
# package:
# name:
# - base-devel
# - git
# state: present
# - name: Disable sudo password prompt (makepkg sudoers hack)
# lineinfile:
# dest: /etc/sudoers
# state: present
# regexp: "^#?%wheel"
# line: "%wheel ALL=(ALL) NOPASSWD: ALL"
# validate: /usr/sbin/visudo -cf %s
# - command:
# cmd: whoami
# no_log: true
# become: false
# register: main_user
# - set_fact:
# main_user: "{{ main_user.stdout }}"
# no_log: true
# - name: Create paru sources dir
# file:
# path: "{{ paru_src_path }}"
# state: directory
# owner: "{{ main_user }}"
# - name: Clone git sources
# become: false
# git:
# repo: "{{ paru_git_repo }}"
# dest: "{{ paru_src_path }}"
# # note: this only works because SUDOERS password prompt is disabled
# - name: Build and install
# become: false
# command:
# chdir: "{{ paru_src_path }}"
# cmd: "makepkg -si -f --noconfirm"
# - name: Restore sudo with password prompt
# lineinfile:
# dest: /etc/sudoers
# state: present
# regexp: "^#?%wheel"
# line: "%wheel ALL=(ALL:ALL) ALL"
# validate: /usr/sbin/visudo -cf %s
# when: not paru.stat.exists
block: block:
- name: Get the last github release - name: Get the last github release
ansible.builtin.uri: ansible.builtin.uri:
@ -13,14 +71,14 @@
register: paru_release register: paru_release
- name: Extract tag_name - name: Extract tag_name
set_fact: ansible.builtin.set_fact:
paru_version: "{{ (paru_release.json.tag_name | regex_replace('^v', '')) }}" paru_version: "{{ (paru_release.json.tag_name | regex_replace('^v', '')) }}"
- name: Get the binary URL ({{ os_arch }}) - name: Get the binary URL ({{ os_arch }})
set_fact: ansible.builtin.set_fact:
paru_url: "{{ item.browser_download_url }}" paru_url: "{{ item.browser_download_url }}"
loop: "{{ paru_release.json.assets }}" loop: "{{ paru_release.json.assets }}"
when: "'{{ os_arch }}.tar.zst' in item.name" when: "'os_arch.tar.zst' in item.name"
- name: Download - name: Download
ansible.builtin.get_url: ansible.builtin.get_url:
@ -45,61 +103,3 @@
ansible.builtin.file: ansible.builtin.file:
path: "/tmp/paru-{{ os_arch }}.tar.zst" path: "/tmp/paru-{{ os_arch }}.tar.zst"
state: absent state: absent
when: not paru.stat.exists
##
## Deprecated version with compilation
##
# - name: Install paru
# block:
# - name: Install build dependencies
# package:
# name:
# - base-devel
# - git
# state: present
# - name: Disable sudo password prompt (makepkg sudoers hack)
# lineinfile:
# dest: /etc/sudoers
# state: present
# regexp: "^#?%wheel"
# line: "%wheel ALL=(ALL) NOPASSWD: ALL"
# validate: /usr/sbin/visudo -cf %s
# - command:
# cmd: whoami
# no_log: true
# become: false
# register: main_user
# - set_fact:
# main_user: "{{ main_user.stdout }}"
# no_log: true
# - name: Create paru sources dir
# file:
# path: "{{ paru_src_path }}"
# state: directory
# owner: "{{ main_user }}"
# - name: Clone git sources
# become: false
# git:
# repo: "{{ paru_git_repo }}"
# dest: "{{ paru_src_path }}"
# # note: this only works because SUDOERS password prompt is disabled
# - name: Build and install
# become: false
# command:
# chdir: "{{ paru_src_path }}"
# cmd: "makepkg -si -f --noconfirm"
# - name: Restore sudo with password prompt
# lineinfile:
# dest: /etc/sudoers
# state: present
# regexp: "^#?%wheel"
# line: "%wheel ALL=(ALL:ALL) ALL"
# validate: /usr/sbin/visudo -cf %s
# when: not paru.stat.exists

View File

@ -1,60 +1,60 @@
--- ---
- name: Check if yay is already installed - name: Check if yay is already installed
stat: ansible.builtin.stat:
path: /usr/bin/yay path: /usr/bin/yay
register: yay register: yay
- name: Install yay - name: Install yay
when: not yay.stat.exists
block: block:
- name: Install build dependencies - name: Install build dependencies
package: ansible.builtin.package:
name: name:
- base-devel - base-devel
- git - git
state: present state: present
- name: Disable sudo password prompt (makepkg sudoers hack) - name: Disable sudo password prompt (makepkg sudoers hack)
lineinfile: ansible.builtin.lineinfile:
dest: /etc/sudoers dest: /etc/sudoers
state: present state: present
regexp: "^#?%wheel" regexp: "^#?%wheel"
line: "%wheel ALL=(ALL) NOPASSWD: ALL" line: "%wheel ALL=(ALL) NOPASSWD: ALL"
validate: /usr/sbin/visudo -cf %s validate: /usr/sbin/visudo -cf %s
- command: - ansible.builtin.command:
cmd: whoami cmd: whoami
no_log: true no_log: true
become: false become: false
register: main_user register: main_user
- set_fact: - ansible.builtin.set_fact:
main_user: "{{ main_user.stdout }}" main_user: "{{ main_user.stdout }}"
no_log: true no_log: true
- name: Create yay sources dir - name: Create yay sources dir
file: ansible.builtin.file:
path: "{{ yay_src_path }}" path: "{{ yay_src_path }}"
state: directory state: directory
owner: "{{ main_user }}" owner: "{{ main_user }}"
- name: Clone git sources - name: Clone git sources
become: false become: false
git: ansible.builtin.git:
repo: "{{ yay_git_repo }}" repo: "{{ yay_git_repo }}"
dest: "{{ yay_src_path }}" dest: "{{ yay_src_path }}"
# note: this only works because SUDOERS password prompt is disabled # note: this only works because SUDOERS password prompt is disabled
- name: Build and install - name: Build and install
become: false become: false
command: ansible.builtin.command:
chdir: "{{ yay_src_path }}" chdir: "{{ yay_src_path }}"
cmd: "makepkg -si -f --noconfirm" cmd: "makepkg -si -f --noconfirm"
- name: Restore sudo with password prompt - name: Restore sudo with password prompt
lineinfile: ansible.builtin.lineinfile:
dest: /etc/sudoers dest: /etc/sudoers
state: present state: present
regexp: "^#?%wheel" regexp: "^#?%wheel"
line: "%wheel ALL=(ALL:ALL) ALL" line: "%wheel ALL=(ALL:ALL) ALL"
validate: /usr/sbin/visudo -cf %s validate: /usr/sbin/visudo -cf %s
when: not yay.stat.exists

View File

@ -1 +1,2 @@
---
ssd_trim_periodicity: monthly ssd_trim_periodicity: monthly

View File

@ -1,7 +1,7 @@
--- ---
- name: Ensure disks are formatted correctly - name: Ensure disks are formatted correctly
include_tasks: partitioning.yml ansible.builtin.include_tasks: partitioning.yml
loop: "{{ disk_partitioning | default([]) }}" loop: "{{ disk_partitioning | default([]) }}"
- name: Enable trim SSD if there is at least one - name: Enable trim SSD if there is at least one
include_tasks: trim-ssd.yml ansible.builtin.include_tasks: trim-ssd.yml

View File

@ -1,23 +1,23 @@
--- ---
- name: Install sfdisk - name: Install sfdisk
package: ansible.builtin.package:
name: util-linux name: util-linux
state: present state: present
changed_when: false changed_when: false
- name: Install hdparm - name: Install hdparm
package: ansible.builtin.package:
name: hdparm name: hdparm
state: present state: present
changed_when: false changed_when: false
- name: Load expected layout from file (controller side) - name: Load expected layout from file (controller side)
set_fact: ansible.builtin.set_fact:
expected_layout: "{{ lookup('file', item.layout_file) }}" expected_layout: "{{ lookup('file', item.layout_file) }}"
changed_when: false changed_when: false
- name: Get current layout from remote - name: Get current layout from remote
command: "sfdisk --dump {{ item.device }}" ansible.builtin.command: "sfdisk --dump {{ item.device }}"
register: current_layout register: current_layout
changed_when: false changed_when: false
@ -25,18 +25,18 @@
vars: vars:
current_clean: "{{ current_layout.stdout | trim | regex_replace('\\s+', ' ') }}" current_clean: "{{ current_layout.stdout | trim | regex_replace('\\s+', ' ') }}"
expected_clean: "{{ expected_layout | trim | regex_replace('\\s+', ' ') }}" expected_clean: "{{ expected_layout | trim | regex_replace('\\s+', ' ') }}"
set_fact: ansible.builtin.set_fact:
layout_differs: "{{ current_clean != expected_clean }}" layout_differs: "{{ current_clean != expected_clean }}"
changed_when: false changed_when: false
- name: Copy layout file to remote (only if different) - name: Copy layout file to remote (only if different)
copy: ansible.builtin.copy:
content: "{{ expected_layout }}" content: "{{ expected_layout }}"
dest: "/tmp/expected-{{ item.device | basename }}.sfdisk" dest: "/tmp/expected-{{ item.device | basename }}.sfdisk"
mode: "0644" mode: "0644"
when: layout_differs when: layout_differs
- name: Apply partition table using sfdisk - name: Apply partition table using sfdisk
command: > ansible.builtin.command: >
sfdisk {{ item.device }} < {{ item.layout_file }} sfdisk {{ item.device }} < {{ item.layout_file }}
when: layout_differs when: layout_differs

View File

@ -1,22 +1,22 @@
--- ---
# see: https://wiki.archlinux.org/title/Solid_state_drive#Periodic_TRIM # see: https://wiki.archlinux.org/title/Solid_state_drive#Periodic_TRIM
- name: Check if there is at least one SSD - name: Check if there is at least one SSD
set_fact: ansible.builtin.set_fact:
has_at_least_one_ssd: "{{ ansible_facts.devices | dict2items | selectattr('value.rotational', 'equalto', '0') | list | length > 0}}" has_at_least_one_ssd: "{{ ansible_facts.devices | dict2items | selectattr('value.rotational', 'equalto', '0') | list | length > 0 }}"
changed_when: false changed_when: false
- name: Skip trim role - name: Skip trim role
meta: end_play ansible.builtin.meta: end_play
when: not has_at_least_one_ssd when: not has_at_least_one_ssd
- name: install trim tools - name: Install trim tools
package: ansible.builtin.package:
name: util-linux name: util-linux
state: present state: present
changed_when: false changed_when: false
- name: edit trim periodicity if needed - name: Edit trim periodicity if needed
template: ansible.builtin.template:
src: templates/fstrim.timer.j2 src: templates/fstrim.timer.j2
dest: "/etc/systemd/system/fstrim.timer.d/override.conf" dest: "/etc/systemd/system/fstrim.timer.d/override.conf"
owner: root owner: root
@ -24,20 +24,20 @@
mode: "0644" mode: "0644"
register: timer_config register: timer_config
- name: systemd daemon reload - name: Systemd daemon reload
systemd: ansible.builtin.systemd:
daemon_reload: yes daemon_reload: true
when: timer_config.changed when: timer_config.changed
- name: enable periodic trim - name: Enable periodic trim
systemd: ansible.builtin.systemd:
name: fstrim.timer name: fstrim.timer
enabled: yes enabled: true
state: started state: started
changed_when: false changed_when: false
- name: install nvme-cli - name: Install nvme-cli
package: ansible.builtin.package:
name: nvme-cli name: nvme-cli
state: present state: present
changed_when: false changed_when: false

View File

@ -1 +1,2 @@
---
docker_projects_dir: /opt/docker docker_projects_dir: /opt/docker

View File

@ -5,49 +5,49 @@
# Archlinux: only if your target is meant to frequently build docker images # Archlinux: only if your target is meant to frequently build docker images
# see: https://stackoverflow.com/a/78352698 # see: https://stackoverflow.com/a/78352698
- name: uninstall docker - name: Uninstall docker
block:
- name: Include uninstall tasks
include_tasks: uninstall.yml
- name: Skip docker installation
meta: end_play
when: uninstall_docker | lower in ['yes', 'y'] when: uninstall_docker | lower in ['yes', 'y']
- name: install docker block:
package: - name: Include uninstall tasks
ansible.builtin.include_tasks: uninstall.yml
- name: Skip docker installation
ansible.builtin.meta: end_play
- name: Install docker
ansible.builtin.package:
name: docker name: docker
- name: enable the service - name: Enable the service
service: ansible.builtin.service:
name: "docker" name: "docker"
enabled: true enabled: true
state: started state: started
- command: - ansible.builtin.command:
cmd: whoami cmd: whoami
no_log: true no_log: true
become: false become: false
register: main_user register: main_user
- set_fact: - ansible.builtin.set_fact:
main_user: "{{ main_user.stdout }}" main_user: "{{ main_user.stdout }}"
no_log: true no_log: true
- name: create projects directory - name: Create projects directory
file: ansible.builtin.file:
path: "{{ docker_projects_dir }}" path: "{{ docker_projects_dir }}"
state: directory state: directory
owner: "{{ main_user }}" owner: "{{ main_user }}"
group: "{{ main_user }}" group: "{{ main_user }}"
- name: allow user to use docker - name: Allow user to use docker
user: ansible.builtin.user:
name: "{{ main_user }}" name: "{{ main_user }}"
groups: docker groups: docker
append: yes append: true
register: docker_group register: docker_group
- name: inform the user that user needs to logout and login again - name: Inform the user that user needs to logout and login again
debug: ansible.builtin.debug:
msg: "Please logout and login again to make sure the user is added to the docker group" msg: "Please logout and login again to make sure the user is added to the docker group"
when: docker_group.changed when: docker_group.changed

View File

@ -1,17 +1,17 @@
--- ---
- name: uninstall docker - name: Uninstall docker
package: ansible.builtin.package:
name: docker name: docker
state: absent state: absent
- name: prompt the user for confirmation - name: Prompt the user for confirmation
ansible.builtin.pause: ansible.builtin.pause:
prompt: "[IRREVERSIBLE] Are you sure you want to delete {{ docker_projects_dir }}?" prompt: "[IRREVERSIBLE] Are you sure you want to delete {{ docker_projects_dir }}?"
echo: yes echo: true
register: confirmation register: confirmation
- name: remote projects directory - name: Remote projects directory
file: ansible.builtin.file:
path: "{{ docker_projects_dir }}" path: "{{ docker_projects_dir }}"
state: absent state: absent
owner: "{{ main_user }}" owner: "{{ main_user }}"

View File

@ -1,2 +1,3 @@
---
fail2ban_firewall: ufw fail2ban_firewall: ufw
fail2ban_backend: systemd fail2ban_backend: systemd

View File

@ -1,27 +1,27 @@
--- ---
# see: https://wiki.archlinux.org/title/Fail2ban # see: https://wiki.archlinux.org/title/Fail2ban
- name: Install fail2ban - name: Install fail2ban
package: ansible.builtin.package:
name: fail2ban name: fail2ban
state: present state: present
- name: Ensure fail2ban configuration is only owned by root - name: Ensure fail2ban configuration is only owned by root
file: ansible.builtin.file:
path: /etc/fail2ban path: /etc/fail2ban
owner: root owner: root
group: root group: root
mode: 0700 mode: "0700"
recurse: yes recurse: true
- name: Install Fail2ban Config - name: Install Fail2ban Config
block: block:
- name: General configuration - name: General configuration
template: ansible.builtin.template:
src: jail.local.j2 src: jail.local.j2
dest: /etc/fail2ban/jail.local dest: /etc/fail2ban/jail.local
mode: "0600" mode: "0600"
- name: Service custom jail - name: Service custom jail
template: ansible.builtin.template:
src: "{{ item.src }}" src: "{{ item.src }}"
dest: "{{ item.dest }}" dest: "{{ item.dest }}"
mode: "0600" mode: "0600"
@ -32,28 +32,28 @@
- name: Service hardening (read-only root rights) - name: Service hardening (read-only root rights)
block: block:
- name: Check if hardening configuration is already applied - name: Check if hardening configuration is already applied
stat: ansible.builtin.stat:
path: /etc/systemd/system/fail2ban.service.d/override.conf path: /etc/systemd/system/fail2ban.service.d/override.conf
register: override_conf register: override_conf
- name: Create configuration directory - name: Create configuration directory
file: ansible.builtin.file:
path: /etc/systemd/system/fail2ban.service.d path: /etc/systemd/system/fail2ban.service.d
state: directory state: directory
owner: root owner: root
group: root group: root
mode: 0700 mode: "0700"
- name: Apply hardening configuration - name: Apply hardening configuration
template: ansible.builtin.template:
src: hardened.fail2ban.conf.j2 src: hardened.fail2ban.conf.j2
dest: /etc/systemd/system/fail2ban.service.d/override.conf dest: /etc/systemd/system/fail2ban.service.d/override.conf
when: not override_conf.stat.exists when: not override_conf.stat.exists
- name: Reload systemd - name: Reload systemd
systemd: ansible.builtin.systemd:
daemon_reload: yes daemon_reload: true
when: not override_conf.stat.exists when: not override_conf.stat.exists
- name: Start and enable fail2ban - name: Start and enable fail2ban
service: ansible.builtin.service:
name: fail2ban name: fail2ban
state: started state: started
enabled: yes enabled: true

View File

@ -1,3 +1,4 @@
---
- name: install oryx - name: install oryx
cmd: paru -S oryx cmd: paru -S oryx
when: ansible_facts['os_family'] == 'Archlinux' when: ansible_facts['os_family'] == 'Archlinux'

View File

@ -1,19 +1,19 @@
--- ---
- name: Check if the interface ipv4 address is defined - name: Check if the interface ipv4 address is defined
block:
- debug:
msg: "Warning: iface {{ interface.name }} has no defined ipv4 address, skipping configuration"
- name: Skip net-config role for {{ interface.name }}
meta: end_play
when: interface.ipv4.address is not defined when: interface.ipv4.address is not defined
block:
- ansible.builtin.debug:
msg: "Warning: iface {{ interface.name }} has no defined ipv4 address, skipping configuration"
- name: Skip net-config role for {{ interface.name }}
ansible.builtin.meta: end_play
- name: Check if the interface is already configured - name: Check if the interface is already configured
stat: ansible.builtin.stat:
path: /etc/systemd/network/20-{{ interface.name }}.network path: /etc/systemd/network/20-{{ interface.name }}.network
register: network_file register: network_file
- name: What patch is needed - name: What patch is needed
debug: ansible.builtin.debug:
msg: >- msg: >-
{%- if network_file.stat.exists == true -%} {%- if network_file.stat.exists == true -%}
iface {{ interface.name }} is already configured, no action needed. iface {{ interface.name }} is already configured, no action needed.
@ -23,7 +23,7 @@
- name: Create systemd-network link file - name: Create systemd-network link file
when: network_file.stat.exists != true when: network_file.stat.exists != true
template: ansible.builtin.template:
src: systemd.network.j2 src: systemd.network.j2
dest: /etc/systemd/network/20-{{ interface.name }}.network dest: /etc/systemd/network/20-{{ interface.name }}.network
owner: root owner: root
@ -31,6 +31,6 @@
mode: "0644" mode: "0644"
- name: Notify a reload is required - name: Notify a reload is required
set_fact: ansible.builtin.set_fact:
network_reload_required: true network_reload_required: true
when: network_file.stat.exists != true when: network_file.stat.exists != true

View File

@ -1,17 +1,11 @@
--- ---
- name: "Check {{ interface.name }} ({{ interface.mac_address }}) rule" - name: "Check {{ interface.name }} ({{ interface.mac_address }}) rule"
set_fact: ansible.builtin.set_fact:
interface_original_name: "{{ ansible_facts.interfaces interface_original_name: "{{ ansible_facts.interfaces | select('in', ansible_facts) | map('extract', ansible_facts) | selectattr('pciid', 'defined') | selectattr('macaddress',
| select('in', ansible_facts) 'equalto', interface.mac_address) | map(attribute='device') | first }}"
| map('extract', ansible_facts)
| selectattr('pciid', 'defined')
| selectattr('macaddress', 'equalto', interface.mac_address)
| map(attribute='device')
| first
}}"
- name: What patch is needed - name: What patch is needed
debug: ansible.builtin.debug:
msg: >- msg: >-
{%- if interface_original_name != interface.name -%} {%- if interface_original_name != interface.name -%}
iface {{ interface_original_name }} ({{ interface.mac_address }}) will be patched to {{ interface.name }}. iface {{ interface_original_name }} ({{ interface.mac_address }}) will be patched to {{ interface.name }}.
@ -21,7 +15,7 @@
- name: Create persistent-net link file - name: Create persistent-net link file
when: interface_original_name != interface.name when: interface_original_name != interface.name
template: ansible.builtin.template:
src: persistent-net.link.j2 src: persistent-net.link.j2
dest: /etc/systemd/network/10-persistent-net-{{ interface.name }}.link dest: /etc/systemd/network/10-persistent-net-{{ interface.name }}.link
owner: root owner: root
@ -29,6 +23,6 @@
mode: "0644" mode: "0644"
- name: Notify a reboot is required - name: Notify a reboot is required
set_fact: ansible.builtin.set_fact:
reboot_required: true reboot_required: true
when: interface_original_name != interface.name when: interface_original_name != interface.name

View File

@ -1,25 +1,25 @@
--- ---
- name: Setup persistent network interface(s) - name: Setup persistent network interface(s)
include_role: ansible.builtin.include_role:
name: net-persist name: net-persist
public: yes public: true
vars: vars:
interface: "{{ item }}" interface: "{{ item }}"
loop: "{{ hostvars[inventory_hostname].network_interfaces | default([]) }}" loop: "{{ hostvars[inventory_hostname].network_interfaces | default([]) }}"
- name: Configure network interface(s) - name: Configure network interface(s)
include_role: ansible.builtin.include_role:
name: net-config name: net-config
public: yes public: true
vars: vars:
interface: "{{ item }}" interface: "{{ item }}"
loop: "{{ hostvars[inventory_hostname].network_interfaces | default([]) }}" loop: "{{ hostvars[inventory_hostname].network_interfaces | default([]) }}"
- name: Reload networkd and resolved - name: Reload networkd and resolved
systemd: ansible.builtin.systemd:
name: "{{ item }}" name: "{{ item }}"
state: reloaded state: reloaded
daemon_reload: yes daemon_reload: true
loop: loop:
- systemd-networkd - systemd-networkd
- systemd-resolved - systemd-resolved

View File

@ -8,7 +8,6 @@
# - host: "192.168.1.0/24" # readonly access for other lan clients # - host: "192.168.1.0/24" # readonly access for other lan clients
# options: "ro,sync,no_subtree_check" # options: "ro,sync,no_subtree_check"
nfs_shares: [] nfs_shares: []
nfs_configuration_file: "/etc/nfs.conf" nfs_configuration_file: "/etc/nfs.conf"
nfs_exports_file: "/etc/exports" nfs_exports_file: "/etc/exports"

View File

@ -3,7 +3,7 @@
ansible.builtin.systemd: ansible.builtin.systemd:
name: "nfsv4-server" name: "nfsv4-server"
state: restarted state: restarted
daemon_reload: yes daemon_reload: true
- name: "Update exportfs" - name: "Update exportfs"
ansible.builtin.command: exportfs -ra ansible.builtin.command: exportfs -ra

View File

@ -1,10 +1,10 @@
--- ---
- name: install nfs-server - name: Install nfs-server
package: ansible.builtin.package:
name: "{{ (ansible_facts['os_family'] == 'Archlinux') | ternary('nfs-utils', 'nfs-kernel-server') }}" name: "{{ (ansible_facts['os_family'] == 'Archlinux') | ternary('nfs-utils', 'nfs-kernel-server') }}"
state: present state: present
- name: configure nfs configuration - name: Configure nfs configuration
ansible.builtin.template: ansible.builtin.template:
src: templates/nfs.conf.j2 src: templates/nfs.conf.j2
dest: "{{ nfs_configuration_file }}" dest: "{{ nfs_configuration_file }}"
@ -13,7 +13,7 @@
mode: "0644" mode: "0644"
notify: Reload systemd and restart nfs-server notify: Reload systemd and restart nfs-server
- name: configure nfs-server exports - name: Configure nfs-server exports
ansible.builtin.template: ansible.builtin.template:
src: templates/exports.j2 src: templates/exports.j2
dest: "{{ nfs_exports_file }}" dest: "{{ nfs_exports_file }}"
@ -22,13 +22,13 @@
mode: "0644" mode: "0644"
notify: Update exportfs notify: Update exportfs
- name: systemd service for nfs-server is started and enabled - name: Systemd service for nfs-server is started and enabled
ansible.builtin.systemd: ansible.builtin.systemd:
name: nfsv4-server name: nfsv4-server
state: started state: started
enabled: true enabled: true
- name: setup firewall rules for nfs on port - name: Setup firewall rules for nfs on port
community.general.ufw: community.general.ufw:
rule: allow rule: allow
src: "{{ item }}" src: "{{ item }}"

View File

@ -1,11 +1,9 @@
---
# NTP configuration file # NTP configuration file
ntp_config_file: "/etc/ntp.conf" ntp_config_file: "/etc/ntp.conf"
# NTP servers to use. # NTP servers to use.
ntp_pools: -" 0.uk.pool.ntp.org" ntp_pools: -" 0.uk.pool.ntp.org" -" 1.uk.pool.ntp.org" -" 2.uk.pool.ntp.org" -" 3.uk.pool.ntp.org"
-" 1.uk.pool.ntp.org"
-" 2.uk.pool.ntp.org"
-" 3.uk.pool.ntp.org"
# System timezone # System timezone
ntp_timezone: "Europe/London" ntp_timezone: "Europe/London"

View File

@ -3,4 +3,4 @@
ansible.builtin.systemd: ansible.builtin.systemd:
name: ntpd name: ntpd
state: restarted state: restarted
daemon_reload: yes daemon_reload: true

View File

@ -1,16 +1,16 @@
--- ---
- name: install NTP package - name: Install NTP package
package: ansible.builtin.package:
name: "ntp" name: "ntp"
state: present state: present
update_cache: yes update_cache: true
- name: set system timezone to {{ ntp_timezone }}" - name: Set system timezone to {{ ntp_timezone }}"
community.general.timezone: community.general.timezone:
name: "{{ ntp_timezone }}" name: "{{ ntp_timezone }}"
notify: "Restart ntpd service" notify: "Restart ntpd service"
- name: ensure NTP drift file directory exists - name: Ensure NTP drift file directory exists
ansible.builtin.file: ansible.builtin.file:
path: "{{ ntp_drift_file | dirname }}" path: "{{ ntp_drift_file | dirname }}"
state: directory state: directory
@ -18,12 +18,12 @@
group: "ntp" group: "ntp"
mode: "0750" mode: "0750"
- name: setup systems timezone - name: Setup systems timezone
community.general.timezone: community.general.timezone:
name: "{{ ntp_timezone }}" name: "{{ ntp_timezone }}"
notify: Restart chronyd # Redémarrer chrony peut être utile après un changement de TZ pour qu'il la prenne bien en compte dans ses logs/opérations notify: Restart chronyd # Redémarrer chrony peut être utile après un changement de TZ pour qu'il la prenne bien en compte dans ses logs/opérations
- name: "configure {{ ntp_config_file }}" - name: "Configure {{ ntp_config_file }}"
ansible.builtin.template: ansible.builtin.template:
src: "ntp.conf.j2" src: "ntp.conf.j2"
dest: "{{ ntp_config_file }}" dest: "{{ ntp_config_file }}"
@ -32,13 +32,13 @@
mode: "0644" mode: "0644"
notify: "Restart ntpd service" notify: "Restart ntpd service"
- name: "ensure ntpd service is started and enabled" - name: "Ensure ntpd service is started and enabled"
ansible.builtin.systemd: ansible.builtin.systemd:
name: "ntpd" name: "ntpd"
state: started state: started
enabled: true enabled: true
- name: "configure ufw firewall" - name: "Configure ufw firewall"
community.general.ufw: community.general.ufw:
rule: allow rule: allow
port: "{{ ntp_port }}" port: "{{ ntp_port }}"

14
roles/sshd/README.md Normal file
View File

@ -0,0 +1,14 @@
# SSH server
## Enable authorized_keys fallback
When you encrypt your home data, you cannot allow hardened remote SSH connection.
To make this still possible, here is the trick: a fallback authorized_key file: /etc/ssh/authorized_keys/myuser
Simply enable this setting to get this working:
```
ssh_authorized_keys_fallback_enabled: true
```
And you're set.

View File

@ -1,3 +1,4 @@
---
ssh_port: 22 ssh_port: 22
ssh_allowed_network: "192.168.1.0/24" ssh_allowed_network: "192.168.1.0/24"
ssh_allowed_vpn_network: "192.168.27.0/27" ssh_allowed_vpn_network: "192.168.27.0/27"

View File

@ -17,7 +17,7 @@
- name: Enable SSH - name: Enable SSH
service: service:
name: "{{ ssh_service_name }}" name: "{{ ssh_service_name }}"
enabled: yes enabled: true
- name: Allow local network incoming connection - name: Allow local network incoming connection
ufw: ufw:

View File

@ -1,2 +1,3 @@
---
ssh_package_name: "openssh" ssh_package_name: "openssh"
ssh_service_name: "sshd" ssh_service_name: "sshd"

View File

@ -1,2 +1,3 @@
---
ssh_package_name: "openssh-server" ssh_package_name: "openssh-server"
ssh_service_name: "ssh" ssh_service_name: "ssh"

View File

@ -1,3 +1,4 @@
---
unbound_config_base_path: /etc/unbound unbound_config_base_path: /etc/unbound
unbound_config_path: "{{ unbound_config_base_path }}/unbound.conf" unbound_config_path: "{{ unbound_config_base_path }}/unbound.conf"
unbound_root_hints_path: "{{ unbound_config_base_path }}/root.hints" unbound_root_hints_path: "{{ unbound_config_base_path }}/root.hints"

View File

@ -9,7 +9,7 @@
ansible.builtin.systemd: ansible.builtin.systemd:
name: unbound name: unbound
state: restarted state: restarted
daemon_reload: yes daemon_reload: true
- name: Reload AppArmor profile - name: Reload AppArmor profile
ansible.builtin.command: apparmor_parser -r {{ unbound_apparmor_profile_path }} ansible.builtin.command: apparmor_parser -r {{ unbound_apparmor_profile_path }}

View File

@ -1,19 +1,19 @@
--- ---
# see: https://calomel.org/unbound_dns.html # see: https://calomel.org/unbound_dns.html
# see: https://wiki.archlinux.org/title/Unbound # see: https://wiki.archlinux.org/title/Unbound
- name: install unbound - name: Install unbound
package: ansible.builtin.package:
name: unbound name: unbound
state: present state: present
# Note: on archlinux this is already shipped within unbound # Note: on archlinux this is already shipped within unbound
- name: install unbound-anchor on debian/ubuntu - name: Install unbound-anchor on debian/ubuntu
package: ansible.builtin.package:
name: unbound-anchor name: unbound-anchor
state: present state: present
when: ansible_facts['os_family'] == 'Debian' when: ansible_facts['os_family'] == 'Debian'
- name: ensure unbound configuration is owned by unbound - name: Ensure unbound configuration is owned by unbound
ansible.builtin.shell: | ansible.builtin.shell: |
find "{{ unbound_config_base_path }}" -type d -exec chmod 755 {} \; find "{{ unbound_config_base_path }}" -type d -exec chmod 755 {} \;
find "{{ unbound_config_base_path }}" -type f -exec chmod 644 {} \; find "{{ unbound_config_base_path }}" -type f -exec chmod 644 {} \;
@ -21,7 +21,7 @@
args: args:
executable: /bin/bash executable: /bin/bash
- name: ensure apparmor profile for unbound exists - name: Ensure apparmor profile for unbound exists
ansible.builtin.copy: ansible.builtin.copy:
dest: /etc/apparmor.d/usr.sbin.unbound dest: /etc/apparmor.d/usr.sbin.unbound
content: | content: |
@ -34,59 +34,59 @@
notify: notify:
- Reload AppArmor profile - Reload AppArmor profile
- name: check if root.hints exists - name: Check if root.hints exists
stat: ansible.builtin.stat:
path: "{{ unbound_root_hints_path }}" path: "{{ unbound_root_hints_path }}"
register: root_hints register: root_hints
- name: update root.hints (if older than 6 months or missing) - name: Update root.hints (if older than 6 months or missing)
when: >
(not root_hints.stat.exists) or
(ansible_date_time.epoch | int - root_hints.stat.mtime > 15552000)
block: block:
- name: download latest root hints from internic - name: Download latest root hints from internic
ansible.builtin.get_url: ansible.builtin.get_url:
url: https://www.internic.net/domain/named.root url: https://www.internic.net/domain/named.root
dest: "{{ unbound_root_hints_path }}" dest: "{{ unbound_root_hints_path }}"
owner: unbound owner: unbound
group: unbound group: unbound
mode: "0644" mode: "0644"
when: > - name: Check if unbound ad_servers configuration exists
(not root_hints.stat.exists) or ansible.builtin.stat:
(ansible_date_time.epoch | int - root_hints.stat.mtime > 15552000)
- name: check if unbound ad_servers configuration exists
stat:
path: "{{ unbound_ad_servers_config_path }}" path: "{{ unbound_ad_servers_config_path }}"
register: ad_servers register: ad_servers
- name: update the ad_servers list if older than 2 weeks or missing - name: Update the ad_servers list if older than 2 weeks or missing
when: >
(not ad_servers.stat.exists) or
(ansible_date_time.epoch | int - ad_servers.stat.mtime > 1209600)
block: block:
- name: download stevenblack's hosts file - name: Download stevenblack's hosts file
ansible.builtin.get_url: ansible.builtin.get_url:
url: https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts url: https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
dest: /tmp/hosts.txt dest: /tmp/hosts.txt
mode: "0644" mode: "0644"
- name: convert hosts file to unbound format - name: Convert hosts file to unbound format
ansible.builtin.shell: | ansible.builtin.shell: |
grep '^0\.0\.0\.0' /tmp/hosts.txt | awk '{print "local-zone: \""$2"\" always_nxdomain"}' > "{{ unbound_ad_servers_config_path }}" && grep '^0\.0\.0\.0' /tmp/hosts.txt | awk '{print "local-zone: \""$2"\" always_nxdomain"}' > "{{ unbound_ad_servers_config_path }}" &&
chown unbound:unbound "{{ unbound_ad_servers_config_path }}" chown unbound:unbound "{{ unbound_ad_servers_config_path }}"
args: args:
executable: /bin/bash executable: /bin/bash
- name: clean up temporary file - name: Clean up temporary file
ansible.builtin.file: ansible.builtin.file:
path: /tmp/hosts.txt path: /tmp/hosts.txt
state: absent state: absent
when: > - name: Initialize dnssec trust anchor if missing
(not ad_servers.stat.exists) or
(ansible_date_time.epoch | int - ad_servers.stat.mtime > 1209600)
- name: initialize dnssec trust anchor if missing
ansible.builtin.command: unbound-anchor -a {{ unbound_anchor_root_key }} ansible.builtin.command: unbound-anchor -a {{ unbound_anchor_root_key }}
args: args:
creates: "{{ unbound_anchor_root_key }}" creates: "{{ unbound_anchor_root_key }}"
- name: install unbound config - name: Install unbound config
template: ansible.builtin.template:
src: "{{ item.src }}" src: "{{ item.src }}"
dest: "{{ item.dest }}" dest: "{{ item.dest }}"
owner: unbound owner: unbound
@ -99,14 +99,14 @@
- Check Unbound config syntax - Check Unbound config syntax
- Reload systemd and restart unbound - Reload systemd and restart unbound
- name: make sure unbound starts after wg-quick@wg0 - name: Make sure unbound starts after wg-quick@wg0
block: block:
- name: ensure unbound.service.d directory exists - name: Ensure unbound.service.d directory exists
ansible.builtin.file: ansible.builtin.file:
path: /etc/systemd/system/unbound.service.d path: /etc/systemd/system/unbound.service.d
state: directory state: directory
mode: "0755" mode: "0755"
- name: configure unbound systemd service - name: Configure unbound systemd service
ansible.builtin.copy: ansible.builtin.copy:
dest: /etc/systemd/system/unbound.service.d/override.conf dest: /etc/systemd/system/unbound.service.d/override.conf
content: | content: |
@ -115,13 +115,13 @@
Requires=wg-quick@wg0.service Requires=wg-quick@wg0.service
notify: Reload systemd and restart unbound notify: Reload systemd and restart unbound
- name: enables unbound service - name: Enables unbound service
ansible.builtin.service: ansible.builtin.service:
name: unbound name: unbound
enabled: yes enabled: true
state: started state: started
- name: firewall ufw rules for unbound - name: Firewall ufw rules for unbound
community.general.ufw: community.general.ufw:
rule: allow rule: allow
port: "{{ unbound_port }}" port: "{{ unbound_port }}"

View File

@ -1,3 +1,4 @@
---
wireguard_primary_interface: "{{ network_interfaces.0.name }}" wireguard_primary_interface: "{{ network_interfaces.0.name }}"
wireguard_port: 51820 # static port to receive input connections wireguard_port: 51820 # static port to receive input connections
wireguard_server_mode: true # enables NAT and open port wireguard_server_mode: true # enables NAT and open port

View File

@ -1,58 +1,59 @@
- name: install wireguard ---
package: - name: Install wireguard
ansible.builtin.package:
name: "{{ (ansible_facts['os_family'] == 'Archlinux') | ternary('wireguard-tools', 'wireguard') }}" name: "{{ (ansible_facts['os_family'] == 'Archlinux') | ternary('wireguard-tools', 'wireguard') }}"
state: present state: present
# to support "DNS=" if used in a "client way" # to support "DNS=" if used in a "client way"
- name: install openresolv/resolveconf - name: Install openresolv/resolveconf
package: ansible.builtin.package:
name: "{{ (ansible_facts['os_family'] == 'Archlinux') | ternary('openresolv', 'resolvconf') }}" name: "{{ (ansible_facts['os_family'] == 'Archlinux') | ternary('openresolv', 'resolvconf') }}"
state: present state: present
- name: ensure wireguard configuration is only owned by root - name: Ensure wireguard configuration is only owned by root
file: ansible.builtin.file:
path: "{{ wireguard_config_base_path }}" path: "{{ wireguard_config_base_path }}"
owner: root owner: root
group: root group: root
mode: 0700 mode: "0700"
recurse: yes recurse: true
- name: check if private key exists - name: Check if private key exists
stat: ansible.builtin.stat:
path: "{{ wireguard_config_base_path }}/privatekey" path: "{{ wireguard_config_base_path }}/privatekey"
register: pkey_file register: pkey_file
- name: generate wireguard keys if not present - name: Generate wireguard keys if not present
shell: wg genkey | tee {{ wireguard_config_base_path }}/privatekey | wg pubkey > {{ wireguard_config_base_path }}/publickey ansible.builtin.shell: wg genkey | tee {{ wireguard_config_base_path }}/privatekey | wg pubkey > {{ wireguard_config_base_path }}/publickey
when: not pkey_file.stat.exists when: not pkey_file.stat.exists
- name: retrieve wireguard private key from file - name: Retrieve wireguard private key from file
slurp: ansible.builtin.slurp:
src: "{{ wireguard_config_base_path }}/privatekey" src: "{{ wireguard_config_base_path }}/privatekey"
register: private_key register: private_key
- name: set wireguard private key - name: Set wireguard private key
set_fact: ansible.builtin.set_fact:
wireguard_private_key: "{{ private_key['content'] | b64decode }}" wireguard_private_key: "{{ private_key['content'] | b64decode }}"
- name: disable "dns=" instruction if unbound is used to avoid race conditions at startup - name: Disable "dns=" instruction if unbound is used to avoid race conditions at startup
set_fact: ansible.builtin.set_fact:
wireguard_dns: wireguard_dns:
when: unbound_custom_lan_records is defined when: unbound_custom_lan_records is defined
- name: install wireguard config - name: Install wireguard config
template: ansible.builtin.template:
src: wireguard.conf.j2 src: wireguard.conf.j2
dest: /etc/wireguard/{{ wireguard_interface }}.conf dest: /etc/wireguard/{{ wireguard_interface }}.conf
- name: start and enable service - name: Start and enable service
service: ansible.builtin.service:
name: wg-quick@{{ wireguard_interface }} name: wg-quick@{{ wireguard_interface }}
state: started state: started
enabled: yes enabled: true
daemon_reload: yes daemon_reload: true
- name: configure the firewall for wireguard - name: Configure the firewall for wireguard
community.general.ufw: community.general.ufw:
rule: allow rule: allow
port: "{{ wireguard_port }}" port: "{{ wireguard_port }}"

View File

@ -1,14 +1,14 @@
--- ---
# due to Ansible limitations, we cannot loop over a block, so we loop over a distinct tasks file... # due to Ansible limitations, we cannot loop over a block, so we loop over a distinct tasks file...
# @see https://stackoverflow.com/a/58911694 # @see https://stackoverflow.com/a/58911694
- name: set ownership on dataset mountpoint - name: Set ownership on dataset mountpoint
block: block:
- name: get the mountpoint - name: Get the mountpoint
ansible.builtin.shell: "zfs get -H -o value mountpoint {{ dataset.name }}" ansible.builtin.command: "zfs get -H -o value mountpoint {{ dataset.name }}"
register: mountpoint register: mountpoint
changed_when: false changed_when: false
- name: set owner of mountpoints - name: Set owner of mountpoints
file: ansible.builtin.file:
path: "{{ mountpoint.stdout }}" path: "{{ mountpoint.stdout }}"
owner: "{{ dataset.user | default(main_user) }}" owner: "{{ dataset.user | default(main_user) }}"
group: "{{ dataset.group | default(main_user) }}" group: "{{ dataset.group | default(main_user) }}"

View File

@ -1,25 +1,25 @@
--- ---
# see: https://docs.ansible.com/ansible/latest/collections/community/general/zfs_module.html # see: https://docs.ansible.com/ansible/latest/collections/community/general/zfs_module.html
- name: managing filesystems, volumes, snapshots - name: Managing filesystems, volumes, snapshots
zfs: community.general.zfs:
name: "{{ item.name }}" name: "{{ item.name }}"
state: "{{ item.state }}" state: "{{ item.state }}"
extra_zfs_properties: "{{ item.extra_zfs_properties|default(omit) }}" extra_zfs_properties: "{{ item.extra_zfs_properties | default(omit) }}"
origin: "{{ item.origin|default(omit) }}" origin: "{{ item.origin | default(omit) }}"
with_items: "{{ zfs_datasets }}" with_items: "{{ zfs_datasets }}"
- command: - ansible.builtin.command:
cmd: whoami cmd: whoami
no_log: true no_log: true
become: false become: false
register: main_user register: main_user
- set_fact: - ansible.builtin.set_fact:
main_user: "{{ main_user.stdout }}" main_user: "{{ main_user.stdout }}"
no_log: true no_log: true
- name: set dataset ownership - name: Set dataset ownership
include_tasks: "./dataset-ownership.yml" ansible.builtin.include_tasks: "./dataset-ownership.yml"
loop: "{{ zfs_datasets }}" loop: "{{ zfs_datasets }}"
loop_control: loop_control:
loop_var: dataset loop_var: dataset

View File

@ -1,12 +1,12 @@
--- ---
# due to Ansible limitations, we cannot loop over a block, so we loop over a distinct tasks file... # due to Ansible limitations, we cannot loop over a block, so we loop over a distinct tasks file...
# @see https://stackoverflow.com/a/58911694 # @see https://stackoverflow.com/a/58911694
- name: prompt the user for confirmation - name: Prompt the user for confirmation
ansible.builtin.pause: ansible.builtin.pause:
prompt: "[IRREVERSIBLE] Are you sure you want to delete zpool {{ zpool.name }}?" prompt: "[IRREVERSIBLE] Are you sure you want to delete zpool {{ zpool.name }}?"
echo: yes echo: true
register: confirmation register: confirmation
- name: deleting zpool - name: Deleting zpool
ansible.builtin.command: "zpool destroy {{ zpool.name }}" ansible.builtin.command: "zpool destroy {{ zpool.name }}"
when: confirmation.user_input | lower in ['yes', 'y'] when: confirmation.user_input | lower in ['yes', 'y']

View File

@ -1,6 +1,6 @@
--- ---
- name: Check if zfs-linux-lts is installed - name: Check if zfs-linux-lts is installed
command: pacman -Qi zfs-dkms ansible.builtin.command: pacman -Qi zfs-dkms
register: zfs_dkms_installed register: zfs_dkms_installed
changed_when: false changed_when: false
failed_when: false failed_when: false
@ -8,9 +8,9 @@
- name: Install zfs - name: Install zfs
when: zfs_dkms_installed.stderr when: zfs_dkms_installed.stderr
block: block:
- name: disable SUDOERS password prompt for makepkg - name: Disable SUDOERS password prompt for makepkg
no_log: true no_log: true
lineinfile: ansible.builtin.lineinfile:
dest: /etc/sudoers dest: /etc/sudoers
state: present state: present
regexp: "^#?%wheel" regexp: "^#?%wheel"
@ -22,30 +22,29 @@
# Using dkms with the lts linux kernel is a better approach IMO. # Using dkms with the lts linux kernel is a better approach IMO.
- name: Install zfs - name: Install zfs
become: false become: false
command: ansible.builtin.command:
cmd: "paru -S --noconfirm zfs-dkms zfs-utils" cmd: "paru -S --noconfirm zfs-dkms zfs-utils"
- name: Restore SUDOERS password prompt after yay - name: Restore SUDOERS password prompt after yay
no_log: true no_log: true
lineinfile: ansible.builtin.lineinfile:
dest: /etc/sudoers dest: /etc/sudoers
state: present state: present
regexp: "^#?%wheel" regexp: "^#?%wheel"
line: "%wheel ALL=(ALL:ALL) ALL" line: "%wheel ALL=(ALL:ALL) ALL"
validate: /usr/sbin/visudo -cf %s validate: /usr/sbin/visudo -cf %s
- name: check if /etc/hostid is present - name: Check if /etc/hostid is present
stat: ansible.builtin.stat:
path: /etc/hostid path: /etc/hostid
register: hostid register: hostid
changed_when: false changed_when: false
- name: generate /etc/hostid if not present - name: Generate /etc/hostid if not present
when: not hostid.stat.exists when: not hostid.stat.exists
command: zgenhostid $(hostid) ansible.builtin.command: zgenhostid $(hostid)
- name: Check if zrepl is installed - name: Check if zrepl is installed
command: pacman -Qi zrepl ansible.builtin.command: pacman -Qi zrepl
register: zrepl_installed register: zrepl_installed
changed_when: false changed_when: false
failed_when: false failed_when: false
@ -53,9 +52,9 @@
- name: Install zrepl - name: Install zrepl
when: zrepl_installed.stderr when: zrepl_installed.stderr
block: block:
- name: disable SUDOERS password prompt for makepkg - name: Disable SUDOERS password prompt for makepkg
no_log: true no_log: true
lineinfile: ansible.builtin.lineinfile:
dest: /etc/sudoers dest: /etc/sudoers
state: present state: present
regexp: "^#?%wheel" regexp: "^#?%wheel"
@ -64,12 +63,12 @@
- name: Install zrepl - name: Install zrepl
become: false become: false
command: ansible.builtin.command:
cmd: "paru -S --noconfirm zrepl" cmd: "paru -S --noconfirm zrepl"
- name: Restore SUDOERS password prompt after paru - name: Restore SUDOERS password prompt after paru
no_log: true no_log: true
lineinfile: ansible.builtin.lineinfile:
dest: /etc/sudoers dest: /etc/sudoers
state: present state: present
regexp: "^#?%wheel" regexp: "^#?%wheel"
@ -77,7 +76,7 @@
validate: /usr/sbin/visudo -cf %s validate: /usr/sbin/visudo -cf %s
- name: Enable zfs services - name: Enable zfs services
service: ansible.builtin.service:
name: "{{ item }}" name: "{{ item }}"
enabled: true enabled: true
state: started state: started

View File

@ -1,9 +1,7 @@
--- ---
- name: Install ZFS - name: Install ZFS
include_tasks: install.yml ansible.builtin.include_tasks: install.yml
- name: Configure Zpools - name: Configure Zpools
include_tasks: pools.yml ansible.builtin.include_tasks: pools.yml
- name: "Setup ZFS datasets: filesystems, snapshots, volumes" - name: "Setup ZFS datasets: filesystems, snapshots, volumes"
include_tasks: datasets.yml ansible.builtin.include_tasks: datasets.yml

View File

@ -3,21 +3,22 @@
# Based on: https://github.com/mrlesmithjr/ansible-zfs/blob/master/tasks/manage_zfs.yml # Based on: https://github.com/mrlesmithjr/ansible-zfs/blob/master/tasks/manage_zfs.yml
# Expected variables in your inventory: zfs_pools. # Expected variables in your inventory: zfs_pools.
- name: checking existing zpool(s) - name: Checking existing zpool(s)
ansible.builtin.shell: "zpool list -H -o name" ansible.builtin.command: "zpool list -H -o name"
changed_when: false changed_when: false
register: current_zp_state register: current_zp_state
check_mode: no check_mode: false
when: zfs_pools is defined when: zfs_pools is defined
- name: gather zpool status - name: Gather zpool status
ansible.builtin.shell: zpool status ansible.builtin.command: zpool status
changed_when: false changed_when: false
register: zpool_devices register: zpool_devices
when: zfs_pools is defined when: zfs_pools is defined
- name: creating basic zpool(s) - name: Creating basic zpool(s)
ansible.builtin.command: "zpool create {{ '-o '+ item.options.items() |map('join', '=') | join (' -o ') if item.options is defined else '' }} {{ item.name }} {{ item.devices|join (' ') }}" ansible.builtin.command: "zpool create {{ '-o '+ item.options.items() |map('join', '=') | join (' -o ') if item.options is defined else '' }} {{ item.name }} {{
item.devices|join (' ') }}"
with_items: "{{ zfs_pools }}" with_items: "{{ zfs_pools }}"
when: when:
- zfs_pools is defined - zfs_pools is defined
@ -26,8 +27,9 @@
- item.state == "present" - item.state == "present"
- item.devices[0] not in zpool_devices.stdout - item.devices[0] not in zpool_devices.stdout
- name: creating mirror/zraid zpool(s) - name: Creating mirror/zraid zpool(s)
ansible.builtin.command: "zpool create {{ '-o '+ item.options.items() |map('join', '=') | join (' -o ') if item.options is defined else '' }} {{ item.name }} {{ item.type }} {{ item.devices|join (' ') }}" ansible.builtin.command: "zpool create {{ '-o '+ item.options.items() |map('join', '=') | join (' -o ') if item.options is defined else '' }} {{ item.name }} {{
item.type }} {{ item.devices|join (' ') }}"
with_items: "{{ zfs_pools }}" with_items: "{{ zfs_pools }}"
when: when:
- zfs_pools is defined - zfs_pools is defined
@ -36,8 +38,8 @@
- item.state == "present" - item.state == "present"
- item.devices[0] not in zpool_devices.stdout - item.devices[0] not in zpool_devices.stdout
- name: deleting zpool(s) with care - name: Deleting zpool(s) with care
include_tasks: "./delete-pool.yml" ansible.builtin.include_tasks: "./delete-pool.yml"
when: when:
- zfs_pools is defined - zfs_pools is defined
- zpool.name in current_zp_state.stdout_lines - zpool.name in current_zp_state.stdout_lines

View File

@ -1,3 +1,4 @@
---
zsh_home: "{{ '/root' if zsh_user == 'root' else '/home/' + zsh_user }}" zsh_home: "{{ '/root' if zsh_user == 'root' else '/home/' + zsh_user }}"
zsh_base_config: "{{ zsh_home }}/.zshrc" zsh_base_config: "{{ zsh_home }}/.zshrc"
zsh_config_path: "{{ zsh_home }}/.config/zsh" zsh_config_path: "{{ zsh_home }}/.config/zsh"

View File

@ -1,14 +1,13 @@
--- ---
- name: install zsh - name: Install zsh
package: ansible.builtin.package:
name: zsh name: zsh
state: present state: present
- name: install zsh plugins - name: Install zsh plugins
include_tasks: plugins.yml ansible.builtin.include_tasks: plugins.yml
- name: Setup zsh for the user(s)
- name: setup zsh for the user(s) ansible.builtin.include_tasks: user-setup.yml
include_tasks: user-setup.yml
vars: vars:
zsh_user: "{{ item }}" zsh_user: "{{ item }}"
loop: "{{ zsh_users | default([]) }}" loop: "{{ zsh_users | default([]) }}"

View File

@ -1,5 +1,5 @@
--- ---
- name: ensure plugins directory exists - name: Ensure plugins directory exists
ansible.builtin.file: ansible.builtin.file:
path: "{{ zsh_plugins_path }}" path: "{{ zsh_plugins_path }}"
state: directory state: directory
@ -7,7 +7,7 @@
group: users group: users
mode: "0755" mode: "0755"
- name: add a readme file to advice from where this comes - name: Add a readme file to advice from where this comes
ansible.builtin.copy: ansible.builtin.copy:
dest: "{{ zsh_plugins_path }}/README.md" dest: "{{ zsh_plugins_path }}/README.md"
content: | content: |
@ -17,27 +17,18 @@
group: users group: users
owner: root owner: root
- name: "git clone plugins" - name: "Git clone plugins"
git: ansible.builtin.git:
repo: "{{ item.repo }}" repo: "{{ item.repo }}"
dest: "{{ item.dest }}" dest: "{{ item.dest }}"
update: yes update: true
version: master version: master
loop: loop:
- { - { repo: https://github.com/zsh-users/zsh-syntax-highlighting.git, dest: "{{ zsh_plugins_path }}/zsh-syntax-highlighting" }
repo: https://github.com/zsh-users/zsh-syntax-highlighting.git, - { repo: https://github.com/zsh-users/zsh-autosuggestions.git, dest: "{{ zsh_plugins_path }}/zsh-autosuggestions" }
dest: "{{ zsh_plugins_path }}/zsh-syntax-highlighting", - { repo: https://github.com/romkatv/powerlevel10k.git, dest: "{{ zsh_plugins_path }}/powerlevel10k" }
}
- {
repo: https://github.com/zsh-users/zsh-autosuggestions.git,
dest: "{{ zsh_plugins_path }}/zsh-autosuggestions",
}
- {
repo: https://github.com/romkatv/powerlevel10k.git,
dest: "{{ zsh_plugins_path }}/powerlevel10k",
}
- name: assert plugins are available for any user - name: Assert plugins are available for any user
ansible.builtin.file: ansible.builtin.file:
path: "{{ item }}" path: "{{ item }}"
owner: root owner: root

View File

@ -1,4 +1,5 @@
- name: setup zsh base config ---
- name: Setup zsh base config
ansible.builtin.template: ansible.builtin.template:
src: main.zshrc.j2 src: main.zshrc.j2
dest: "{{ zsh_base_config }}" dest: "{{ zsh_base_config }}"
@ -6,7 +7,7 @@
group: "{{ zsh_user }}" group: "{{ zsh_user }}"
mode: "0600" mode: "0600"
- name: setup .config/zsh directory - name: Setup .config/zsh directory
ansible.builtin.file: ansible.builtin.file:
path: "{{ zsh_config_path }}" path: "{{ zsh_config_path }}"
state: directory state: directory
@ -14,7 +15,7 @@
group: "{{ zsh_user }}" group: "{{ zsh_user }}"
mode: "0700" mode: "0700"
- name: configure zsh config - name: Configure zsh config
ansible.builtin.template: ansible.builtin.template:
src: zshrc.j2 src: zshrc.j2
dest: "{{ zsh_config_file }}" dest: "{{ zsh_config_file }}"
@ -22,7 +23,7 @@
group: "{{ zsh_user }}" group: "{{ zsh_user }}"
mode: "0600" mode: "0600"
- name: copy aliases - name: Copy aliases
ansible.builtin.copy: ansible.builtin.copy:
src: ./templates/aliases src: ./templates/aliases
dest: "{{ zsh_config_path }}/aliases" dest: "{{ zsh_config_path }}/aliases"
@ -30,12 +31,12 @@
group: "{{ zsh_user }}" group: "{{ zsh_user }}"
mode: "0600" mode: "0600"
- name: change default shell to zsh - name: Change default shell to zsh
user: ansible.builtin.user:
name: "{{ zsh_user }}" name: "{{ zsh_user }}"
shell: /bin/zsh shell: /bin/zsh
- name: configure powerlevel10k theme - name: Configure powerlevel10k theme
ansible.builtin.copy: ansible.builtin.copy:
src: "./templates/{{ 'root.p10k.zsh' if zsh_user == 'root' else 'user.p10k.zsh' }}" src: "./templates/{{ 'root.p10k.zsh' if zsh_user == 'root' else 'user.p10k.zsh' }}"
dest: "{{ zsh_p10k_theme_config }}" dest: "{{ zsh_p10k_theme_config }}"