work-vm/ansible/provision.yml

640 lines
20 KiB
YAML

- hosts: localhost
become: true
vars:
# Debian packages that must be installed
debian_packages:
- acl
- bat
- bind9
- build-essential
- console-common
- console-setup
- containerd.io
- curl
- dialog
- docker-buildx-plugin
- docker-ce
- docker-ce-cli
- docker-compose-plugin
- firefox-esr
- fzf
- gawk
- git
- htop
- ipcalc
- iptables-persistent
- keepassxc
- ldap-utils
- libldap2-dev
- libsasl2-dev
- libvirt-clients
- libvirt-daemon
- libvirt-daemon-config-network
- libvirt-daemon-driver-qemu
- libvirt-daemon-system
- libvirt-daemon-system-systemd
- libvirt-dbus
- lua5.4
- net-tools
- psmisc
- python3-dev
- python3-pip
- qemu-guest-agent
- qemu-kvm
- remmina
- spice-vdagent
- sshpass
- task-xfce-desktop
- unzip
- vim-gtk3
- virt-manager
- zsh
# Version of ASDF itself
asdf_version: 0.15.0
# Tools that will be installed using asdf
asdf_tools:
- java
- golang
- nodejs
- opentofu
- packer
- terragrunt
# If some asdf-installed tools require specific versions, they must be
# listed here. Tools that are not listed will default to the latest
# version.
asdf_tool_versions:
java: openjdk-17
nodejs: 22.12.0
opentofu: 1.8.1
packer: 1.11.0
terragrunt: 0.66.9
# Python packages to install
python_packages:
- ansible>=9,<10
- dnspython
- netaddr
- python-ldap
- xmltodict
- pyvmomi
- requests
- git+https://github.com/vmware/vsphere-automation-sdk-python.git
- pywinrm
# Version of the git-delta utility
git_delta_version: 0.18.2
# Version of the atuin utility
atuin_version: 18.4.0
# Vim plugins that need to be installed
vim_plugins:
- airblade/vim-gitgutter
- bling/vim-airline
- cespare/vim-toml
- ctrlpvim/ctrlp.vim
- elzr/vim-json
- Exafunction/codeium.vim
- fatih/vim-go
- Glench/Vim-Jinja2-Syntax
- hashivim/vim-terraform
- liuchengxu/vim-which-key
- mattn/vim-lsp-settings
- mbbill/undotree
- octol/vim-cpp-enhanced-highlight
- PProvost/vim-ps1
- prabirshrestha/asyncomplete-lsp.vim
- prabirshrestha/asyncomplete.vim
- prabirshrestha/async.vim
- prabirshrestha/vim-lsp
- rbong/vim-flog
- rust-lang/rust.vim
- scrooloose/nerdtree
- Shougo/dein.vim
- skywind3000/asyncrun.vim
- tikhomirov/vim-glsl
- tpope/vim-fugitive
- vim-airline/vim-airline-themes
- vim-perl/vim-perl
- vim-test/vim-test
- wsdjeg/dein-ui.vim
- Xuyuanp/nerdtree-git-plugin
# Various parameters need to be fetched from env variables
domain_name: >-
{{ lookup( "env", "VMNET_DOMAIN" ) }}
update_key: >-
{{ lookup( "env", "VMNET_BIND_KEY_ID" ) }}
back_net: >-
{{ lookup( "env" , "VMNET_BACK_ADDR" ) }}
front_net: >-
{{ lookup( "env" , "VMNET_FRONT_ADDR" ) }}
back_arpa: >-
{{ back_net.split( "." )[0:3] | reverse | join( "." ) }}.in-addr.arpa
front_arpa: >-
{{ front_net.split( "." )[0:3] | reverse | join( "." ) }}.in-addr.arpa
locale: >-
{{ lookup( "env", "VM_LOCALE" ) }}
chezmoi_source: >-
{{ lookup( "env", "CHEZMOI_SOURCE" ) }}
tasks:
# Configure grub
- name: Reduce boot delay to 1s
ansible.builtin.lineinfile:
path: /etc/default/grub
regexp: ^GRUB_TIMEOUT=
line: GRUB_TIMEOUT=1
- name: Update Grub configuration
ansible.builtin.command:
cmd: update-grub2
# Ensure ext4 filesystems are mounted with discard enabled
- name: Add discard option to mount points
loop: [ "/" , "/boot" ]
ansible.builtin.lineinfile:
path: /etc/fstab
backrefs: true
regexp: '^(\S+\s+{{ item }}\s+\S+\s+)(?!(?:\S*,)?discard(?:,\S*)?\s+)(\S+)(\s+.+)$'
line: '\1discard,\2\3'
# Prepare for docker installation
- name: Get APT key for the Docker repo
ansible.builtin.shell:
cmd: wget -O- https://download.docker.com/linux/debian/gpg > /etc/apt/keyrings/docker.asc
- name: Add Docker APT repo
ansible.builtin.shell:
cmd: |
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] http://download.docker.com/linux/debian \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
> /etc/apt/sources.list.d/docker.list
# Install various required packages
- name: Remove unnecessary packages
ansible.builtin.command:
cmd: apt-get autoremove -y
- name: Install packages
ansible.builtin.apt:
update_cache: true
name: "{{ debian_packages }}"
# Keyboard / locale configuration
- name: Copy keyboard config
ansible.builtin.copy:
src: files/keyboard
dest: /etc/default/keyboard
force: true
- name: Copy locale config
ansible.builtin.template:
src: files/locale.j2
dest: /etc/default/locale
force: true
- name: Change locale to {{ locale }}
community.general.locale_gen:
name: "{{ locale }}"
state: present
- name: Set timezone
community.general.timezone:
name: Europe/Paris
- name: dpkg-reconfigure
ansible.builtin.shell: >
dpkg-reconfigure -f noninteractive keyboard-configuration &&
localectl set-locale LANG={{ locale }} LANGUAGE={{ locale }} &&
timedatectl set-timezone Europe/Paris &&
update-locale LANG={{ locale }}
# Desktop resizing
- name: Create desktop resizing logs directory
ansible.builtin.file:
path: /var/log/autores
state: directory
mode: "0700"
- name: Copy desktop resizing script
ansible.builtin.copy:
src: files/resize.sh
dest: /usr/local/bin/x-resize
mode: "0755"
- name: Create udev rule
ansible.builtin.copy:
content: >
ACTION=="change",KERNEL=="card0", SUBSYSTEM=="drm", RUN+="/usr/local/bin/x-resize"
dest: /etc/udev/rules.d/50-x-resize.rules
mode: "0644"
- name: Reload udev rules
ansible.builtin.command:
cmd: udevadm control --reload-rules
# Prevent XFCE from creating random dirs in the user home
- name: Create user config directory
ansible.builtin.file:
path: /home/vagrant/.config
state: directory
owner: vagrant
group: vagrant
- name: Configure XDG user dirs
ansible.builtin.copy:
src: files/user-dirs.dirs
dest: /home/vagrant/.config/user-dirs.dirs
owner: vagrant
group: vagrant
# Configure VM networks
- name: Configure dummy module
ansible.builtin.lineinfile:
path: /etc/modprobe.d/local.conf
create: true
line: options dummy numdummies=0
- name: Configure bridge network devices
loop: [0, 1]
ansible.builtin.copy:
content: |
[NetDev]
Name=br{{ item }}
Kind=bridge
dest: /etc/systemd/network/bridge{{ item }}.netdev
- name: Configure bridge networks
loop:
- { id: 0, addr: "{{ back_net }}" }
- { id: 1, addr: "{{ front_net }}" }
ansible.builtin.copy:
content: |
[Match]
Name=br{{ item.id }}
[Network]
ConfigureWithoutCarrier=yes
LinkLocalAddressing=no
Address={{ item.addr }}/24
dest: /etc/systemd/network/bridge{{ item.id }}.network
- name: Configure dummy network devices
loop: [0, 1]
ansible.builtin.copy:
content: |
[NetDev]
Name=dummy{{ item }}
Kind=dummy
dest: /etc/systemd/network/dummy{{ item }}.netdev
- name: Enslave dummy network devices to bridges
loop: [0, 1]
ansible.builtin.copy:
content: |
[Match]
Name=dummy{{ item }}
[Network]
Bridge=br{{ item }}
ConfigureWithoutCarrier=yes
dest: /etc/systemd/network/dummy{{ item }}.network
- name: Ensure IPv4 forwarding is enabled
ansible.builtin.lineinfile:
path: /etc/systemd/network/eth0.network
line: IPForward=ipv4
insertafter: ^\[Network\]$
- name: Configure NAT
ansible.builtin.copy:
src: files/iptables
dest: /etc/iptables/rules.v4
# Configure DNS server
- name: Disable IPv6 for Bind
ansible.builtin.lineinfile:
path: /etc/default/named
line: OPTIONS="-u bind -4"
regexp: ^OPTIONS=
- name: Generate dynamic update key
when: lookup( "env", "VMNET_BIND_KEY" ) == ""
ansible.builtin.shell:
cmd: >-
tsig-keygen -a hmac-sha512 {{ update_key }}.
> /etc/bind/tf-key.conf
creates: /etc/bind/tf-key.conf
- name: Copy dynamic update key
when: lookup( "env", "VMNET_BIND_KEY" ) != ""
ansible.builtin.template:
src: files/tf-key.conf.j2
dest: /etc/bind/tf-key.conf
- name: Configure Bind options
ansible.builtin.template:
src: files/bind-options
dest: /etc/bind/named.conf.options
owner: root
group: bind
- name: Configure local domains
ansible.builtin.template:
src: files/domains.j2
dest: /etc/bind/named.conf.local
owner: root
group: bind
- name: Initialize zone for domain
ansible.builtin.template:
src: files/zf-domain.j2
dest: /var/lib/bind/db.{{ domain_name }}
owner: bind
group: bind
- name: Initialize reverse DNS zones
loop:
- { arpa: "{{ back_arpa }}" , host: vm-host }
- { arpa: "{{ front_arpa }}" , host: vm-host-f }
ansible.builtin.template:
src: files/zf-reverse.j2
dest: /var/lib/bind/db.{{ item.arpa }}
owner: bind
group: bind
- name: Ensure resolution is enabled for external domains
ansible.builtin.lineinfile:
path: /etc/systemd/network/eth0.network
line: Domains=~.
insertafter: ^\[Network\]$
- name: Configure systemd-resolved so it queries the local DNS server
ansible.builtin.template:
src: files/resolved.conf.j2
dest: /etc/systemd/resolved.conf
# Download and install delta. The asdf-provided version doesn't work on
# Debian.
- name: Download git-delta
ansible.builtin.get_url:
url: https://github.com/dandavison/delta/releases/download/{{ git_delta_version }}/git-delta-musl_{{ git_delta_version }}_amd64.deb
dest: /root
- name: Install git-delta
ansible.builtin.command:
cmd: dpkg -i /root/git-delta-musl_{{ git_delta_version }}_amd64.deb
# Download and install atuin.
- name: Download atuin
ansible.builtin.get_url:
url: https://github.com/atuinsh/atuin/releases/download/v{{ atuin_version }}/atuin-x86_64-unknown-linux-gnu.tar.gz
dest: /tmp
- name: Install atuin
ansible.builtin.command:
cmd: tar xzf /tmp/atuin-x86_64-unknown-linux-gnu.tar.gz --strip-components=1 atuin-x86_64-unknown-linux-gnu/atuin
chdir: /usr/local/bin
# Ensure virtualization and docker can be used
- name: Add the vagrant user to various group
ansible.builtin.user:
name: vagrant
groups: kvm,libvirt,docker
append: true
- name: Make the QEMU bridge helper setuid
ansible.builtin.file:
path: /usr/lib/qemu/qemu-bridge-helper
group: kvm
mode: "6750"
- name: Allow QEMU tu use br0
ansible.builtin.copy:
content: allow br0
dest: /etc/qemu/bridge.conf
- name: Disable libvirt security driver
ansible.builtin.lineinfile:
path: /etc/libvirt/qemu.conf
regexp: ^security_driver\s*=
line: >-
security_driver = "none"
# Set the shell to zsh for the vagrant user
- name: Set default shell
ansible.builtin.user:
name: vagrant
shell: /bin/zsh
# "Fix" X11 forwarding
- name: Fix X11 forwarding through SSH
ansible.builtin.copy:
dest: /etc/ssh/sshd_config.d/x11forwarding.conf
content: |
X11UseLocalhost no
- name: Configure user account
become: false
block:
- name: Create directories for zsh and other tools
loop:
- .local/share/zsh
- .local/bin
- .config/atuin
- .ssh
ansible.builtin.file:
state: directory
path: /home/vagrant/{{ item }}
mode: "0755"
owner: vagrant
group: vagrant
# Install ASDF
- name: Install ASDF
ansible.builtin.git:
repo: https://github.com/asdf-vm/asdf.git
dest: /home/vagrant/.asdf
single_branch: true
version: v{{ asdf_version }}
# Install and run Chezmoi
- name: Install chezmoi
ansible.builtin.shell:
cmd: >-
set -e ;
export ASDF_DIR=/home/vagrant/.asdf ;
. $ASDF_DIR/asdf.sh ;
asdf plugin-add chezmoi ;
asdf install chezmoi latest ;
asdf global chezmoi latest
chdir: /home/vagrant
- name: Check for known host
when: >-
chezmoi_source is match( "^ssh://" )
check_mode: true
ansible.builtin.lineinfile:
path: /home/vagrant/.ssh/known_hosts
line: "^{{ chezmoi_source | urlsplit( 'hostname' ) }} "
regex: true
state: absent
register: ssh_key_present
- name: Add SSH key for chezmoi's Git repo
when: >-
chezmoi_source is match( "^ssh://" ) and
ssh_key_present is not changed
ansible.builtin.shell:
cmd: >-
ssh-keyscan {{ chezmoi_source | urlsplit( 'hostname' ) }} \
>> /home/vagrant/.ssh/known_hosts
- name: Check for chezmoi repo
when: chezmoi_source != ""
ansible.builtin.stat:
path: /home/vagrant/.local/share/chezmoi
register: chezmoi_stat
- name: Initialize chezmoi
when: chezmoi_source != "" and not chezmoi_stat.stat.exists
ansible.builtin.shell:
cmd: >-
set -e ;
export ASDF_DIR=/home/vagrant/.asdf ;
. $ASDF_DIR/asdf.sh ;
chezmoi init {{ chezmoi_source }} ;
chezmoi apply
chdir: /home/vagrant
# If there's not .zshrc, use default config files
- name: Check for zshrc
ansible.builtin.stat:
path: /home/vagrant/.zshrc
register: zshrc_stat
- when: not zshrc_stat.stat.exists
block:
# Create the zsh configuration for the vagrant user
- name: Copy configuration files
loop:
- {s: antigen.zsh, d: .local/share/zsh/antigen.zsh}
- {s: p10k.zsh, d: .local/share/zsh/p10k.zsh}
- {s: atuin.toml, d: .config/atuin/config.toml}
- {s: gitconfig, d: .gitconfig}
ansible.builtin.copy:
src: files/{{ item.s }}
dest: /home/vagrant/{{ item.d }}
mode: "0644"
owner: vagrant
group: vagrant
- name: Update configuration files
loop:
- {s: zshrc, d: .zshrc}
ansible.builtin.template:
src: files/{{ item.s }}
dest: /home/vagrant/{{ item.d }}
mode: "0644"
owner: vagrant
group: vagrant
# Initialize shell
- name: Run shell initialization
ansible.builtin.command:
cmd: zsh .zshrc
chdir: /home/vagrant
# Install various tools using asdf
- name: Install asdf plugins
loop: "{{ asdf_tools }}"
ansible.builtin.shell:
cmd: >-
source .zshrc &&
asdf plugin-add {{ item }}
chdir: /home/vagrant
executable: /bin/zsh
register: asdf_out
failed_when: >-
asdf_out.rc != 0 and
'already added' not in asdf_out.stderr
- name: Install tools using asdf
loop: "{{ asdf_tools }}"
ansible.builtin.shell:
cmd: >-
source .zshrc &&
asdf install {{ item }} {{ asdf_tool_versions[ item ] | default( "latest" ) }} &&
asdf global {{ item }} {{ asdf_tool_versions[ item ] | default( "latest" ) }}
chdir: /home/vagrant
executable: /bin/zsh
# Install Ansible 9 and various packages in a Python venv
- name: Ensure vagrant user has a .local directory
loop: [ bin, share ]
ansible.builtin.file:
path: /home/vagrant/.local/{{ item }}
state: directory
- name: Create Ansible virtual environment
ansible.builtin.shell:
executable: /bin/zsh
cmd: >-
source .zshrc && {
[ -d /home/vagrant/.local/share/ansible ] ||
python -m venv /home/vagrant/.local/share/ansible;
}
chdir: /home/vagrant
- name: Install Ansible and related Python packages
ansible.builtin.shell:
executable: /bin/zsh
cmd: >-
source /home/vagrant/.zshrc &&
source /home/vagrant/.local/share/ansible/bin/activate &&
pip install "{{ python_packages | join('" "') }}"
chdir: /home/vagrant/.local/share
- name: List Ansible executables
ansible.builtin.find:
paths: /home/vagrant/.local/share/ansible/bin
file_type: file
patterns: [ "ansible*" ]
register: ansible_exes
- name: Create Ansible symlinks
loop: "{{ ansible_exes.files }}"
ansible.builtin.file:
state: link
src: "{{ item.path }}"
dest: /home/vagrant/.local/bin/{{ item.path | basename }}
# Configure SSH for the vagrant user
- name: Configure SSH for the vagrant user
ansible.builtin.copy:
src: files/ssh_config
dest: /home/vagrant/.ssh/config
# Configure Vim
- name: Remove default vimrc
ansible.builtin.file:
path: /home/vagrant/.vimrc
state: absent
- name: Install vim configuration
ansible.builtin.git:
repo: https://git@git.nocternity.net/tseeker-pub/heavim.git
dest: /home/vagrant/.vim
- name: Create vim cache directory
ansible.builtin.file:
path: /home/vagrant/.cache/vim
state: directory
mode: "0700"
- name: Create vim plugin directories
loop: "{{ vim_plugins | map( 'dirname' ) | unique }}"
ansible.builtin.file:
path: /home/vagrant/.cache/vim/bundles/repos/github.com/{{ item }}
state: directory
- name: Clone vim plugins
loop: "{{ vim_plugins }}"
ansible.builtin.git:
repo: https://github.com/{{ item }}
dest: /home/vagrant/.cache/vim/bundles/repos/github.com/{{ item }}
# Install Rust
- name: Install Rust
ansible.builtin.shell:
cmd: >-
set -e ;
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > /tmp/rustinit.sh ;
sh /tmp/rustinit.sh -y -c rust-analyzer,rust-src,rust-analysis