infra/ansible/playbook.yml

645 lines
18 KiB
YAML

---
- name: Apply common configuration to all nodes
hosts: all
become: true
# become_method: sudo
gather_facts: true
remote_user: ansible
roles:
- base
tags:
- common
tasks:
- name: Set timezone
community.general.timezone:
name: "{{ timezone }}"
- name: Apply firewall configuration
hosts: all:!proxmox_servers
become: true
gather_facts: true
tags:
- firewall
roles:
- firewall
- name: Apply resolver config
hosts: resolvers
become: true
gather_facts: true
tags:
- resolvers
roles:
- resolvers
- caddy
- telegraf
- name: Install and configure NetBox
hosts: netbox_servers
become: true
gather_facts: true
tags:
- netbox
roles:
- netbox
- name: Install and configure Icinga2 monitor
hosts: monitoring_servers
become: true
gather_facts: true
tags:
- monitor
- icinga2
roles:
- monitor
- name: Install and configure Caddy
hosts: caddy_servers
become: true
tags:
- caddy
roles:
- caddy
- name: Configure PostgreSQL servers and PgBouncer
hosts: postgresql_servers
become: true
gather_facts: true
tags:
- postgresql
roles:
- role: base
tags: base
- role: geerlingguy.postgresql
tags: postgres
- role: pgbouncer
tags: pgbouncer
- name: Provision BIND9 VM on Proxmox
hosts: localhost
gather_facts: false
tags:
- dns
- bind9
- provision
- never
vars:
# Proxmox connection settings (matches terraform/variables.tf)
proxmox_node: "{{ lookup('env', 'PROXMOX_NODE') | default('vm2-380', true) }}"
proxmox_api_host: 10.0.0.2
proxmox_api_user: "{{ lookup('env', 'PROXMOX_API_USER') | default('root@pam', true) }}"
proxmox_api_password: "{{ lookup('env', 'PROXMOX_API_PASSWORD') }}"
proxmox_storage: local-lvm
proxmox_template_name: debian-cloud-init
proxmox_template_vmid: 9000
# BIND9 VM configuration
vm_name: ns1.as393837.net
vm_vmid: 222
vm_ip: 204.110.191.222
vm_gateway: 204.110.191.254
vm_netmask: 255.255.255.224
vm_cores: 2
vm_memory: 2048
vm_disk_size: 64
ansible_ssh_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFghGMnDdkfNC6JPEhMxrKhYDmNcXjHXp/y/mf3uLtzb"
tasks:
- name: Clone cloud-init template for BIND9 server
community.proxmox.proxmox_kvm:
node: "{{ proxmox_node }}"
vmid: "{{ proxmox_template_vmid }}"
clone: "{{ proxmox_template_name }}"
newid: "{{ vm_vmid }}"
name: "{{ vm_name }}"
api_user: "{{ proxmox_api_user }}"
api_password: "{{ proxmox_api_password }}"
api_host: "{{ proxmox_api_host }}"
validate_certs: false
storage: "{{ proxmox_storage }}"
timeout: 90
full: true
- name: Configure VM resources
community.proxmox.proxmox_kvm:
node: "{{ proxmox_node }}"
vmid: "{{ vm_vmid }}"
name: "{{ vm_name }}"
api_user: "{{ proxmox_api_user }}"
api_password: "{{ proxmox_api_password }}"
api_host: "{{ proxmox_api_host }}"
validate_certs: false
cores: "{{ vm_cores }}"
memory: "{{ vm_memory }}"
update: true
- name: Resize disk
community.proxmox.proxmox_disk:
vmid: "{{ vm_vmid }}"
api_user: "{{ proxmox_api_user }}"
api_password: "{{ proxmox_api_password }}"
api_host: "{{ proxmox_api_host }}"
validate_certs: false
disk: scsi0
size: "{{ vm_disk_size }}G"
state: resized
- name: Configure cloud-init network
community.proxmox.proxmox_kvm:
node: "{{ proxmox_node }}"
vmid: "{{ vm_vmid }}"
name: "{{ vm_name }}"
api_user: "{{ proxmox_api_user }}"
api_password: "{{ proxmox_api_password }}"
api_host: "{{ proxmox_api_host }}"
validate_certs: false
ipconfig:
ipconfig0: "ip={{ vm_ip }}/26,gw={{ vm_gateway }}"
nameservers:
- 1.1.1.1
- 8.8.8.8
ciuser: debian
cipassword: "sxcbctolxALGnj2R8GStXrfW8GVd3s/ju91fNon7T1U="
update: true
- name: Start VM
community.proxmox.proxmox_kvm:
node: "{{ proxmox_node }}"
vmid: "{{ vm_vmid }}"
name: "{{ vm_name }}"
api_user: "{{ proxmox_api_user }}"
api_password: "{{ proxmox_api_password }}"
api_host: "{{ proxmox_api_host }}"
validate_certs: false
state: started
- name: Wait for VM to be accessible via SSH
ansible.builtin.wait_for:
host: "{{ vm_ip }}"
port: 22
delay: 30
timeout: 300
state: started
- name: Add VM to in-memory inventory
ansible.builtin.add_host:
name: "{{ vm_name }}"
ansible_host: "{{ vm_ip }}"
groups: bind9_servers
- name: Configure BIND9 Servers
hosts: bind9_servers
become: true
gather_facts: true
tags:
- dns
- bind9
roles:
- role: base
tags: base
- role: ns
tags: ns
- name: Build and upload NixOS template to Proxmox
hosts: localhost
gather_facts: false
tags:
- template
- never
vars:
proxmox_node: "{{ lookup('env', 'PROXMOX_NODE') | default('vm2-380', true) }}"
proxmox_api_host: 10.0.0.2
proxmox_api_user: "{{ lookup('env', 'PROXMOX_API_USER') | default('root@pam', true) }}"
proxmox_api_password: "{{ lookup('env', 'PROXMOX_API_PASSWORD') }}"
nixos_template_vmid: 9010
build_host: ci
tasks:
- name: Upload NixOS config to build host
ansible.builtin.copy:
src: files/nixos-template-config.nix
dest: /tmp/nixos-template-config.nix
delegate_to: "{{ build_host }}"
- name: Build NixOS proxmox image
ansible.builtin.shell: >
nixos-generate -f proxmox
-o /tmp/nixos-template.vma.zst
-c /tmp/nixos-template-config.nix
args:
chdir: /tmp
environment:
PATH: "/run/current-system/sw/bin:{{ ansible_env.PATH }}"
delegate_to: "{{ build_host }}"
register: _nixos_build
- name: Find built VMA file in nix store
ansible.builtin.shell: >
nix-shell -p nixos-generators --run
"nixos-generate -f proxmox -o /tmp/nixos-template.vma.zst -c /tmp/nixos-template-config.nix" 2>&1
| grep '^/' | tail -1
args:
chdir: /tmp
delegate_to: "{{ build_host }}"
register: _vma_path
changed_when: false
- name: Copy VMA from build host to Proxmox
ansible.builtin.shell: >
scp {{ build_host }}:'{{ _vma_path.stdout }}' /tmp/nixos-template.vma.zst &&
scp /tmp/nixos-template.vma.zst root@{{ proxmox_api_host }}:/tmp/nixos-template.vma.zst
- name: Destroy existing template VM
community.proxmox.proxmox_kvm:
node: "{{ proxmox_node }}"
vmid: "{{ nixos_template_vmid }}"
api_user: "{{ proxmox_api_user }}"
api_password: "{{ proxmox_api_password }}"
api_host: "{{ proxmox_api_host }}"
validate_certs: false
state: absent
force: true
- name: Create VM and import disk on Proxmox
ansible.builtin.shell: >
set -e;
vma extract /tmp/nixos-template.vma.zst /tmp/nixos-vma;
qm create {{ nixos_template_vmid }} --name nixos-cloud-init
--memory 2048 --cores 2 --net0 virtio,bridge=vmbr0
--scsihw virtio-scsi-pci --ide2 local-lvm:cloudinit
--boot c --bootdisk scsi0 --serial0 socket --vga serial0;
qm importdisk {{ nixos_template_vmid }}
/tmp/nixos-vma/disk-drive-virtio0.raw local-lvm;
qm set {{ nixos_template_vmid }}
--scsi0 "local-lvm:vm-{{ nixos_template_vmid }}-disk-0";
qm template {{ nixos_template_vmid }};
rm -rf /tmp/nixos-vma /tmp/nixos-template.vma.zst
delegate_to: "{{ proxmox_node }}"
- name: Provision NixOS VM on Proxmox
hosts: localhost
gather_facts: false
tags:
- nixos
- provision
- never
vars:
proxmox_node: "{{ lookup('env', 'PROXMOX_NODE') | default('vm2-380', true) }}"
proxmox_api_host: 10.0.0.2
proxmox_api_user: "{{ lookup('env', 'PROXMOX_API_USER') | default('root@pam', true) }}"
proxmox_api_password: "{{ lookup('env', 'PROXMOX_API_PASSWORD') }}"
proxmox_storage: local-lvm
proxmox_template_vmid: 9010
proxmox_template_name: nixos-cloud-init
vm_name: nixos-resolver
vm_vmid: 110
vm_cores: 2
vm_memory: 4096
vm_disk_size: 64
vm_ssh_keys: |
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHLyVSEEAEbGZZqwPwEup0XrlTpu3x3iF9ExvvQPA4xN
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOzrDMNn3nINGdIogzRxY05fkn05LSYi98BGW1Bz5yXD
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIER/8suIKcrT3a/NZHjvOpRosPC5uX4kcznIJHt/98qj
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEEKtgXwoW8HZGqC+KJok9iNpI/lK4glvoryL4Ng/AL+
tasks:
- name: Clone NixOS template
community.proxmox.proxmox_kvm:
node: "{{ proxmox_node }}"
vmid: "{{ proxmox_template_vmid }}"
clone: "{{ proxmox_template_name }}"
newid: "{{ vm_vmid }}"
name: "{{ vm_name }}"
api_user: "{{ proxmox_api_user }}"
api_password: "{{ proxmox_api_password }}"
api_host: "{{ proxmox_api_host }}"
validate_certs: false
storage: "{{ proxmox_storage }}"
timeout: 90
full: true
agent: true
- name: Configure VM resources
community.proxmox.proxmox_kvm:
node: "{{ proxmox_node }}"
vmid: "{{ vm_vmid }}"
name: "{{ vm_name }}"
api_user: "{{ proxmox_api_user }}"
api_password: "{{ proxmox_api_password }}"
api_host: "{{ proxmox_api_host }}"
validate_certs: false
cores: "{{ vm_cores }}"
memory: "{{ vm_memory }}"
update: true
- name: Resize disk
community.proxmox.proxmox_disk:
vmid: "{{ vm_vmid }}"
api_user: "{{ proxmox_api_user }}"
api_password: "{{ proxmox_api_password }}"
api_host: "{{ proxmox_api_host }}"
validate_certs: false
disk: scsi0
size: "{{ vm_disk_size }}G"
state: resized
register: _disk_resize
failed_when:
- _disk_resize.failed
- '"shrinking disks is not supported" not in (_disk_resize.msg | default(""))'
- name: Configure cloud-init
community.proxmox.proxmox_kvm:
node: "{{ proxmox_node }}"
vmid: "{{ vm_vmid }}"
name: "{{ vm_name }}"
api_user: "{{ proxmox_api_user }}"
api_password: "{{ proxmox_api_password }}"
api_host: "{{ proxmox_api_host }}"
validate_certs: false
ciuser: root
sshkeys: "{{ vm_ssh_keys }}"
ipconfig:
ipconfig0: "ip=dhcp"
nameservers:
- 1.1.1.1
onboot: true
update: true
- name: Start VM
community.proxmox.proxmox_kvm:
node: "{{ proxmox_node }}"
vmid: "{{ vm_vmid }}"
name: "{{ vm_name }}"
api_user: "{{ proxmox_api_user }}"
api_password: "{{ proxmox_api_password }}"
api_host: "{{ proxmox_api_host }}"
validate_certs: false
state: started
- name: Wait for VM IP via QEMU agent
ansible.builtin.shell: >
python3 -c "
import urllib3, json, time
urllib3.disable_warnings()
from proxmoxer import ProxmoxAPI
proxmox = ProxmoxAPI('{{ proxmox_api_host }}',
user='{{ proxmox_api_user }}', password='{{ proxmox_api_password }}',
verify_ssl=False)
for _ in range(48):
try:
nets = proxmox.nodes('{{ proxmox_node }}').qemu('{{ vm_vmid }}').agent('network-get-interfaces').get()
for iface in nets.get('result', []):
for addr in iface.get('ip-addresses', []):
if addr.get('ip-address-type') == 'ipv4' and addr['ip-address'] != '127.0.0.1':
print(addr['ip-address'])
exit(0)
time.sleep(5)
except Exception:
time.sleep(5)
exit(1)
"
register: _agent_ip
changed_when: false
retries: 1
delay: 0
- name: Add VM to in-memory inventory
ansible.builtin.add_host:
name: "{{ vm_name }}"
ansible_host: "{{ _agent_ip.stdout | trim }}"
groups: nixos_resolvers
- name: Configure NixOS Unbound resolver
hosts: nixos_resolvers
become: true
gather_facts: true
tags:
- nixos
- unbound
- never
tasks:
- name: Load resolver group variables
ansible.builtin.include_vars:
file: group_vars/resolvers/main.yml
- name: Deploy NixOS configuration with Unbound
ansible.builtin.template:
src: roles/resolvers/templates/nixos-unbound.nix.j2
dest: /etc/nixos/unbound.nix
owner: root
group: root
mode: '0644'
register: _nixos_config
- name: Import unbound module in configuration.nix
ansible.builtin.lineinfile:
path: /etc/nixos/configuration.nix
line: "./unbound.nix"
regexp: '^./unbound\.nix'
insertafter: '^\{ config,'
state: present
register: _nixos_import
- name: Rebuild NixOS
ansible.builtin.command: nixos-rebuild switch
when: _nixos_config.changed or _nixos_import.changed
- name: Apply general configuration to all nodes
hosts: all
become: true
become_method: sudo
roles:
- general
tags:
- general
- name: Configure LibreNMS servers
hosts: librenms_servers
become: true
gather_facts: true
tags:
- librenms
roles:
- librenms
- name: Configure aprsc servers
hosts: aprsc_servers
become: true
gather_facts: true
tags:
- aprsc
roles:
- aprsc
- name: Provision UISP VM on Proxmox
hosts: localhost
gather_facts: false
tags:
- uisp
- provision
- never
vars:
# Proxmox connection settings
proxmox_node: "{{ lookup('env', 'PROXMOX_NODE') | default('vm2-380', true) }}"
proxmox_api_host: 10.0.0.2
proxmox_api_user: "{{ lookup('env', 'PROXMOX_API_USER') | default('root@pam', true) }}"
proxmox_api_password: "{{ lookup('env', 'PROXMOX_API_PASSWORD') }}"
proxmox_storage: local-lvm
proxmox_template_name: debian-cloud-init
proxmox_template_vmid: 9000
# UISP VM configuration
vm_name: uisp.vntx.net
vm_vmid: 224
vm_ip: 204.110.191.224
vm_gateway: 204.110.191.254
vm_cores: 20
vm_memory: 16384
vm_disk_size: 64
vm_vlan: 9
ansible_ssh_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFghGMnDdkfNC6JPEhMxrKhYDmNcXjHXp/y/mf3uLtzb"
tasks:
- name: Clone cloud-init template for UISP server
community.proxmox.proxmox_kvm:
node: "{{ proxmox_node }}"
vmid: "{{ proxmox_template_vmid }}"
clone: "{{ proxmox_template_name }}"
newid: "{{ vm_vmid }}"
name: "{{ vm_name }}"
api_user: "{{ proxmox_api_user }}"
api_password: "{{ proxmox_api_password }}"
api_host: "{{ proxmox_api_host }}"
validate_certs: false
storage: "{{ proxmox_storage }}"
timeout: 90
full: true
- name: Configure VM resources
community.proxmox.proxmox_kvm:
node: "{{ proxmox_node }}"
vmid: "{{ vm_vmid }}"
name: "{{ vm_name }}"
api_user: "{{ proxmox_api_user }}"
api_password: "{{ proxmox_api_password }}"
api_host: "{{ proxmox_api_host }}"
validate_certs: false
cores: "{{ vm_cores }}"
memory: "{{ vm_memory }}"
net:
net0: "virtio,bridge=vmbr0,tag={{ vm_vlan }}"
update: true
- name: Resize disk
community.proxmox.proxmox_disk:
vmid: "{{ vm_vmid }}"
api_user: "{{ proxmox_api_user }}"
api_password: "{{ proxmox_api_password }}"
api_host: "{{ proxmox_api_host }}"
validate_certs: false
disk: scsi0
size: "{{ vm_disk_size }}G"
state: resized
- name: Configure cloud-init network
community.proxmox.proxmox_kvm:
node: "{{ proxmox_node }}"
vmid: "{{ vm_vmid }}"
name: "{{ vm_name }}"
api_user: "{{ proxmox_api_user }}"
api_password: "{{ proxmox_api_password }}"
api_host: "{{ proxmox_api_host }}"
validate_certs: false
ipconfig:
ipconfig0: "ip={{ vm_ip }}/26,gw={{ vm_gateway }}"
nameservers:
- 1.1.1.1
- 8.8.8.8
ciuser: debian
cipassword: "sxcbctolxALGnj2R8GStXrfW8GVd3s/ju91fNon7T1U="
searchdomains: vntx.net
sshkeys: "{{ ansible_ssh_key }}"
update: true
- name: Start VM
community.proxmox.proxmox_kvm:
node: "{{ proxmox_node }}"
vmid: "{{ vm_vmid }}"
name: "{{ vm_name }}"
api_user: "{{ proxmox_api_user }}"
api_password: "{{ proxmox_api_password }}"
api_host: "{{ proxmox_api_host }}"
validate_certs: false
state: started
- name: Wait for VM to be accessible via SSH
ansible.builtin.wait_for:
host: "{{ vm_ip }}"
port: 22
delay: 30
timeout: 300
state: started
- name: Add VM to in-memory inventory
ansible.builtin.add_host:
name: "{{ vm_name }}"
ansible_host: "{{ vm_ip }}"
ansible_user: debian
groups: uisp_servers
- name: Configure UISP servers
hosts: uisp_servers
become: true
gather_facts: true
tags:
- uisp
roles:
- role: base
tags: base
- role: uisp
tags: uisp
- name: Configure Dokku servers
hosts: dokku_servers
become: true
gather_facts: true
tags:
- dokku
roles:
- dokku
- name: Configure node_exporter targets
hosts: node_exporter_servers
become: true
gather_facts: true
tags:
- node_exporter
- prometheus_stack
roles:
- node_exporter
- name: Configure Prometheus monitoring stack
hosts: prometheus_servers
become: true
gather_facts: true
tags:
- prometheus_stack
roles:
- role: alertmanager
tags: alertmanager
- role: prometheus
tags: prometheus
- role: loki
tags: loki
- role: grafana
tags: grafana
- name: Configure IRC servers
hosts: irc_servers
become: true
gather_facts: true
tags:
- irc
- inspircd
roles:
- inspircd