Initial Lab Setup
This commit is contained in:
+23
@@ -0,0 +1,23 @@
|
|||||||
|
# Ansible artifacts
|
||||||
|
*.retry
|
||||||
|
.ansible_cache/
|
||||||
|
|
||||||
|
# Sensitive data (even if currently stored outside the repo)
|
||||||
|
.ansible_vault_pass
|
||||||
|
.env
|
||||||
|
*.token
|
||||||
|
|
||||||
|
# Script outputs
|
||||||
|
unifi_firewall_rules.json
|
||||||
|
|
||||||
|
# Editor-specific files (Vim)
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
|
||||||
|
# OS-specific files (macOS)
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
*.log
|
||||||
|
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
- name: Setup new administrative user
|
||||||
|
hosts: tatooine
|
||||||
|
become: yes # This tells Ansible to run as root
|
||||||
|
remote_user: root
|
||||||
|
vars:
|
||||||
|
new_user: "volker"
|
||||||
|
# Replace this with your actual public key string or a path to the file
|
||||||
|
ssh_public_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCqKm6tSG73CudRxZkUnR/hcwKQnvSfkQM/Gq1gR6wswu4kcthHZ+YCxzRFIJmTR1+C0UXy8yRVtwprz31plFbHvU3Om913MGaN1oadunYOkKD8OmAtCtht9H+5wC5HtjwuhNf/MH1K727ecNUSH10DYovzXkOD6byJukfkvbU6CVKxWAI6W9PXTLOPRyUoy3TX0GEBascayneqHBFfPGpICnR76X9Ydi2avfgmNiGtTMzKkn1mNqm3a4eHCfde8XUBtqlxdMnO/pMlgMh14XoBSD5T+U3OqIUvMOiU3ZKlcq4W46wtPX1Im6iqfgFutwT1YqQ8UNY06urO41nH6d5rVfSA1BS7Fonho2xK5lQ3aqapn2+o9goXTIQ1avoOHyWS0j+W8m5BEL8Prvr+eqjTCivh5g4rKVe2SebKzZU89oZSEkV9Mj69qhS1g3LnyJds+oskl04CdRXrn5KSyxXP9X4m0EYYfbzWMAPRZ6SsltAOw9w4hwZtwIKSl2+bMQAqQmRojDof4FgK+DCQfdcThhrmknGtGiL1v3tJuCmmiikoKis5qOVBmVJOhJaSOTKSIhx3oTVVfCgzlEnGE0M7gUk1+Qh30p4TahsbyfcWg5v3+0vdIVgAWIdW0Kp0s9R0mU4qKeIuZ9ejHCmaGcQe2ZolQZc5UrTwMBb1PaqPQQ== key von macbook fuer rogueone"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Ensure the user exists
|
||||||
|
ansible.builtin.user:
|
||||||
|
name: "{{ new_user }}"
|
||||||
|
state: present
|
||||||
|
shell: /bin/bash
|
||||||
|
groups: sudo # Use 'wheel' if you are on RHEL/CentOS/Fedora
|
||||||
|
append: yes # Ensures you don't remove them from other groups
|
||||||
|
|
||||||
|
- name: Set up authorized keys for the new user
|
||||||
|
ansible.builtin.authorized_key:
|
||||||
|
user: "{{ new_user }}"
|
||||||
|
state: present
|
||||||
|
key: "{{ ssh_public_key }}"
|
||||||
|
|
||||||
|
- name: Allow the user to use sudo without a password (Optional)
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/sudoers.d/{{ new_user }}
|
||||||
|
line: "{{ new_user }} ALL=(ALL) NOPASSWD:ALL"
|
||||||
|
state: present
|
||||||
|
mode: '0440'
|
||||||
|
create: yes
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
[defaults]
|
||||||
|
inventory = inventory.ini
|
||||||
|
# Disable those annoying deprecation warnings
|
||||||
|
deprecation_warnings = False
|
||||||
|
# Make the output more readable (shows time taken for each task)
|
||||||
|
callbacks_enabled = profile_tasks
|
||||||
|
# Optional: Use the 'yaml' callback for much prettier error messages
|
||||||
|
# # Use the default plugin but tell it to format as YAML
|
||||||
|
stdout_callback = default
|
||||||
|
result_format = yaml
|
||||||
|
vault_password_file = ~/.ansible_vault_pass
|
||||||
|
host_key_checking = False
|
||||||
|
collections_path = ~/.ansible/collections:/opt/homebrew/Cellar/ansible/14.0.0/libexec/lib/python3.14/site-packages/ansible_collections
|
||||||
Executable
+28
@@ -0,0 +1,28 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Usage: ./bootstrap_node.sh <IP_ADDRESS> <NEW_HOSTNAME> <REMOTE_USER>
|
||||||
|
IP=$1
|
||||||
|
NEW_HOSTNAME=$2
|
||||||
|
R_USER=${3:-pi} # Defaults to 'pi' if not specified
|
||||||
|
|
||||||
|
echo "🚀 Bootstrapping $NEW_HOSTNAME at $IP..."
|
||||||
|
|
||||||
|
# 1. Push SSH Keys (Mac -> Node)
|
||||||
|
# This removes the need for passwords immediately
|
||||||
|
ssh-copy-id -i ~/.ssh/id_ed25519.pub "$R_USER@$IP"
|
||||||
|
|
||||||
|
# 2. Set Hostname and Passwordless Sudo
|
||||||
|
# We use a single SSH command to minimize login prompts
|
||||||
|
ssh -t "$R_USER@$IP" << EOF
|
||||||
|
sudo hostnamectl set-hostname $NEW_HOSTNAME
|
||||||
|
echo "$R_USER ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/010-$R_USER-nopasswd
|
||||||
|
sudo apt update && sudo apt install -y python3
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "✅ $NEW_HOSTNAME is ready for Ansible!"
|
||||||
|
|
||||||
|
# Append to inventory if not already there
|
||||||
|
if ! grep -q "$NEW_HOSTNAME" inventory.ini; then
|
||||||
|
echo "$NEW_HOSTNAME ansible_host=$IP" >> inventory.ini
|
||||||
|
echo "Added $NEW_HOSTNAME to inventory.ini"
|
||||||
|
fi
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
- name: Sentinel mit der originalen Common-Rolle auf Stand bringen
|
||||||
|
hosts: sentinel
|
||||||
|
gather_facts: yes
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
# Hier sagen wir Ansible, als welcher User er sich JETZT noch einwählen muss
|
||||||
|
vars:
|
||||||
|
ansible_user: root
|
||||||
|
|
||||||
|
roles:
|
||||||
|
- common
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
- name: Fix InfluxData GPG Key expiration (Trixie/sqv fix)
|
||||||
|
become: true
|
||||||
|
block:
|
||||||
|
- name: Download the latest InfluxData archive key
|
||||||
|
ansible.builtin.get_url:
|
||||||
|
url: https://repos.influxdata.com/influxdata-archive.key
|
||||||
|
dest: /tmp/influxdata-archive.key
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
- name: Dearmor key for sqv compatibility
|
||||||
|
ansible.builtin.shell: |
|
||||||
|
cat /tmp/influxdata-archive.key | gpg --dearmor > /usr/share/keyrings/influxdata-archive.gpg
|
||||||
|
args:
|
||||||
|
creates: /usr/share/keyrings/influxdata-archive.gpg
|
||||||
|
|
||||||
|
- name: Ensure correct repository configuration
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /etc/apt/sources.list.d/influxdata.list
|
||||||
|
content: "deb [signed-by=/usr/share/keyrings/influxdata-archive.gpg] https://repos.influxdata.com/debian stable main"
|
||||||
|
|
||||||
|
- name: Remove conflicting legacy list files
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "/etc/apt/sources.list.d/{{ item }}"
|
||||||
|
state: absent
|
||||||
|
loop:
|
||||||
|
- repos_influxdata_com_debian.list
|
||||||
|
- influxdb.list
|
||||||
|
|
||||||
|
- name: Run apt update
|
||||||
|
ansible.builtin.apt:
|
||||||
|
update_cache: yes
|
||||||
Executable
+17
@@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# --- KONFIGURATION ---
|
||||||
|
UNIFI_IP="192.168.123.254"
|
||||||
|
API_TOKEN="DEIN_KOPIERTER_API_TOKEN"
|
||||||
|
OUTPUT_FILE="~/lab-rack/unifi_firewall_rules.json"
|
||||||
|
|
||||||
|
echo "📥 Lade Firewall-Konfiguration via API-Token herunter..."
|
||||||
|
|
||||||
|
# Der offizielle Endpunkt für die Sicherheits- und Firewallkonfiguration
|
||||||
|
curl -s -S -k -X GET \
|
||||||
|
-H "X-API-KEY: $API_TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
"https://$UNIFI_IP/proxy/network/api/v2/sites/default/firewall/rules" \
|
||||||
|
| jq '.' > $(eval echo $OUTPUT_FILE)
|
||||||
|
|
||||||
|
echo "✅ Fertig!"
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
- name: Minimaler Unifi Test
|
||||||
|
hosts: unifi
|
||||||
|
gather_facts: no
|
||||||
|
collections:
|
||||||
|
- community.general
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Unifi Controller-spezifische Facts auslesen
|
||||||
|
unifi_facts:
|
||||||
|
user: "ansible-v2-ro"
|
||||||
|
password: "DeinSicheresReadOnlyPasswort"
|
||||||
|
host: "127.0.0.1"
|
||||||
|
port: 8443
|
||||||
|
validate_certs: no
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
domain_name: "intern.wks20.de"
|
||||||
|
ansible_python_interpreter: "/usr/bin/python3"
|
||||||
|
#root_password_hash: "$6$kJcofjjySrjly.o/$XaP/4a0wDUIHyuykJbzd4k/HbA39SEyhaVE6dKaX7pO1blXR.4A87i45uPHrQ.AxXEvRBzzlgF8rkwCCNKUTf."
|
||||||
|
|
||||||
|
# Security Variables (Encrypted)
|
||||||
|
# Security Variables (Encrypted with your Vault Password)
|
||||||
|
root_password_hash: !vault |
|
||||||
|
$ANSIBLE_VAULT;1.1;AES256
|
||||||
|
61363637383337623138306333386331643636643730333932656537323931666365643861316264
|
||||||
|
3666356131333166663538326266316334313663666663610a346263643932396535383834343065
|
||||||
|
65306530376265316535323962656532323936666562323761306662383962646130373062343233
|
||||||
|
3437373235633966360a343064363464323835636465666538373231323837313164353536663064
|
||||||
|
33356631366662623835306562386637343363343931323833303832326637633663386633653561
|
||||||
|
30376163393431616635643830653061383663383466333132663062633765316463353139363465
|
||||||
|
36383137346266396365643633376139383137626465646236333332376632633639386433333338
|
||||||
|
37363439356236326164396534343737373065643231626238623237643332393761643230653935
|
||||||
|
36346431393530623734356364613933326335363766353539643632336662393066613935643432
|
||||||
|
3931383864393736306638363365353263376162396137316232
|
||||||
|
|
||||||
|
|
||||||
|
common_packages:
|
||||||
|
# --- System Management & Logic ---
|
||||||
|
- sudo
|
||||||
|
- aptitude # Better dependency resolution than standard apt
|
||||||
|
- needrestart # Checks which services need a restart after updates
|
||||||
|
- python3 # Requirement for Ansible
|
||||||
|
- nala
|
||||||
|
|
||||||
|
# --- Networking & Service Discovery ---
|
||||||
|
- avahi-daemon # Enables hostname.local discovery
|
||||||
|
- lldpd # Link Layer Discovery (find physical switch ports)
|
||||||
|
- netcat-traditional
|
||||||
|
- net-tools # Classic 'ifconfig', 'route', etc.
|
||||||
|
- ethtool # Query/Control network driver/hardware
|
||||||
|
- prometheus-node-exporter
|
||||||
|
# --- Diagnostics & Performance Monitoring ---
|
||||||
|
- htop # Interactive process viewer
|
||||||
|
- ncdu # Ncurses disk usage analyzer
|
||||||
|
- btm
|
||||||
|
|
||||||
|
# --- Transfer & Download Tools ---
|
||||||
|
- curl
|
||||||
|
- wget
|
||||||
|
- git
|
||||||
|
- rsync
|
||||||
|
- unzip
|
||||||
|
|
||||||
|
# --- Terminal Multiplexers & Editors ---
|
||||||
|
- screen # Terminal session persistence
|
||||||
|
- tmux # Modern multiplexer
|
||||||
|
- vim # (Already handled by your role, but good to have)
|
||||||
|
|
||||||
|
# --- Storage & File Systems ---
|
||||||
|
- exfatprogs # Essential for mounting your Pi backup drives
|
||||||
|
# Pakete, die nur auf modernem OS laufen (Debian 13+)
|
||||||
|
modern_os_packages:
|
||||||
|
- fastfetch
|
||||||
|
- btm
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
$ANSIBLE_VAULT;1.1;AES256
|
||||||
|
63626431383962356137626330343265373631376364383063363134393563356536663136303532
|
||||||
|
3961663537373834383235373861386262656166643366330a303166363231653262343865613331
|
||||||
|
33363463356565633435346565386630623439633739366363343166323837326366656131316239
|
||||||
|
3631353237353439660a326363316234386562343034336464643132623665363135373437613165
|
||||||
|
36396138383262623761306431383933383762653538313636396430343534333336376235323064
|
||||||
|
3964613232663431393133336466323330376165313435313863
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
samba_shares:
|
||||||
|
|
||||||
|
- name: "stuff"
|
||||||
|
path: "/mnt/data1"
|
||||||
|
force_user: "volker"
|
||||||
|
group: "volker"
|
||||||
|
mode: "0770"
|
||||||
|
read_only: "no"
|
||||||
|
browseable: "yes"
|
||||||
|
guest_ok: "no"
|
||||||
|
|
||||||
|
- name: "tank"
|
||||||
|
path: "/mnt/data2"
|
||||||
|
mode: "0775"
|
||||||
|
read_only: "no"
|
||||||
|
browseable: "yes"
|
||||||
|
guest_ok: "yes"
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
- name: Deploy Telegraf to Goldeneye
|
||||||
|
hosts: endor
|
||||||
|
become: yes
|
||||||
|
tasks:
|
||||||
|
- name: Install Telegraf package
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: telegraf
|
||||||
|
state: present
|
||||||
|
update_cache: yes
|
||||||
|
|
||||||
|
- name: Push Telegraf configuration
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: templates/telegraf.conf.j2
|
||||||
|
dest: /etc/telegraf/telegraf.conf
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
- name: Ensure Telegraf is started and enabled
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: telegraf
|
||||||
|
state: restarted
|
||||||
|
enabled: yes
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
# --- Individual Hosts ---
|
||||||
|
|
||||||
|
[management]
|
||||||
|
sentinel ansible_host=127.0.0.1 ansible_connection=local
|
||||||
|
|
||||||
|
[physical_iron]
|
||||||
|
endor ansible_host=192.168.123.210 # Your Proxmox Host
|
||||||
|
#goldeneye ansible_host=192.168.123.215 # Your Raspberry Pi
|
||||||
|
tatooine ansible_host=192.168.123.211 # Your Proxmox Host 2
|
||||||
|
|
||||||
|
[lxc_containers]
|
||||||
|
jump ansible_host=192.168.123.104
|
||||||
|
smb03 ansible_host=192.168.123.115
|
||||||
|
docker01 ansible_host=192.168.123.100
|
||||||
|
watch-lan ansible_host=192.168.123.103
|
||||||
|
mqtt ansible_host=192.168.111.102
|
||||||
|
paperless ansible_host=192.168.123.105
|
||||||
|
adguard ansible_host=192.168.123.108
|
||||||
|
#debian ansible_host=192.168.123.118
|
||||||
|
syslog ansible_host=192.168.123.109
|
||||||
|
minio ansible_host=192.168.123.110
|
||||||
|
jellyfin ansible_host=192.168.123.114
|
||||||
|
tk-smb02 ansible_host=192.168.123.99
|
||||||
|
podman01 ansible_host=192.168.123.116
|
||||||
|
monitor ansible_host=192.168.123.101
|
||||||
|
|
||||||
|
# Add other VMs here as you create them
|
||||||
|
|
||||||
|
[yunohost_servers]
|
||||||
|
rohan ansible_host=192.168.112.42
|
||||||
|
bumb ansible_host=192.168.112.46
|
||||||
|
|
||||||
|
[proxmox_vms]
|
||||||
|
rohan ansible_host=192.168.112.42
|
||||||
|
proxy ansible_host=192.168.112.7
|
||||||
|
bumb ansible_host=192.168.112.46
|
||||||
|
|
||||||
|
[reverse_proxies]
|
||||||
|
proxy
|
||||||
|
|
||||||
|
# --- Logic Groups (Used by site.yml) ---
|
||||||
|
[monitoring_servers]
|
||||||
|
monitor
|
||||||
|
# This creates 'all_nodes' by nesting the physical and VM groups
|
||||||
|
[all_nodes:children]
|
||||||
|
physical_iron
|
||||||
|
proxmox_vms
|
||||||
|
yunohost_servers
|
||||||
|
lxc_containers
|
||||||
|
|
||||||
|
# Group for the Fileserver role
|
||||||
|
[smb_servers]
|
||||||
|
smb03
|
||||||
|
|
||||||
|
# Group for Backup logic (if you want to expand beyond just Goldeneye)
|
||||||
|
[backup_servers]
|
||||||
|
#goldeneye
|
||||||
|
[unifi]
|
||||||
|
agw01 ansible_host=192.168.123.254
|
||||||
|
|
||||||
|
# --- Connection Variables ---
|
||||||
|
[all:vars]
|
||||||
|
ansible_user=volker
|
||||||
|
ansible_ssh_private_key_file=~/.ssh/id_ed25519
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
---
|
||||||
|
- name: Ensure Proxmox GPG key is present (for Raspberry Pi/PBS)
|
||||||
|
ansible.builtin.get_url:
|
||||||
|
url: https://enterprise.proxmox.com/debian/proxmox-release-trixie.gpg
|
||||||
|
dest: /etc/apt/trusted.gpg.d/proxmox-release-trixie.gpg
|
||||||
|
mode: '0644'
|
||||||
|
become: yes # Added
|
||||||
|
when: ansible_distribution == 'Debian'
|
||||||
|
tags: [setup]
|
||||||
|
|
||||||
|
- name: Set hostname
|
||||||
|
ansible.builtin.hostname:
|
||||||
|
name: "{{ inventory_hostname }}"
|
||||||
|
become: yes # Added
|
||||||
|
tags: [identity]
|
||||||
|
|
||||||
|
- name: Update /etc/hosts for FQDN resolution
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/hosts
|
||||||
|
regexp: '^127\.0\.1\.1'
|
||||||
|
line: "127.0.1.1 {{ inventory_hostname }}.{{ domain_name }} {{ inventory_hostname }}"
|
||||||
|
become: yes # Added
|
||||||
|
tags: [identity]
|
||||||
|
|
||||||
|
- name: Check for NetworkManager
|
||||||
|
ansible.builtin.command: systemctl is-active NetworkManager
|
||||||
|
register: nm_status
|
||||||
|
ignore_errors: yes
|
||||||
|
changed_when: false
|
||||||
|
tags: [identity, network]
|
||||||
|
|
||||||
|
- name: Configure NetworkManager Search Domain (Raspberry Pi/mDNS Style)
|
||||||
|
when: nm_status.rc == 0
|
||||||
|
tags: [identity, network]
|
||||||
|
block:
|
||||||
|
- name: Get active connection name
|
||||||
|
ansible.builtin.shell: "nmcli -t -f NAME connection show --active | head -n 1"
|
||||||
|
register: active_conn
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Apply search domain via nmcli
|
||||||
|
ansible.builtin.command: "nmcli connection modify '{{ active_conn.stdout }}' ipv4.dns-search '{{ domain_name }}'"
|
||||||
|
when: active_conn.stdout != ""
|
||||||
|
notify: Reload NetworkManager
|
||||||
|
|
||||||
|
- name: Configure systemd-resolved Search Domain (Vanilla Debian Style)
|
||||||
|
ansible.builtin.ini_file:
|
||||||
|
path: /etc/systemd/resolved.conf
|
||||||
|
section: Resolve
|
||||||
|
option: Domains
|
||||||
|
value: "{{ domain_name }}"
|
||||||
|
become: yes # Added
|
||||||
|
notify: Restart systemd-resolved
|
||||||
|
when: nm_status.rc != 0
|
||||||
|
tags: [identity, network]
|
||||||
|
|
||||||
|
- name: Set system timezone
|
||||||
|
community.general.timezone:
|
||||||
|
name: Europe/Berlin
|
||||||
|
become: yes
|
||||||
|
tags: [localization]
|
||||||
|
|
||||||
|
#- name: Ensure locales are generated
|
||||||
|
# ansible.builtin.locale_gen:
|
||||||
|
# name: en_US.UTF-8
|
||||||
|
# state: present
|
||||||
|
# become: yes
|
||||||
|
# tags: [localization]
|
||||||
|
|
||||||
|
#- name: Set system locale
|
||||||
|
# ansible.builtin.debconf:
|
||||||
|
# name: locales
|
||||||
|
# question: locales/default_environment_locale
|
||||||
|
# value: en_US.UTF-8
|
||||||
|
# vtype: select
|
||||||
|
# become: yes
|
||||||
|
# tags: [localization]
|
||||||
|
|
||||||
|
#- name: Force 24h clock format globally
|
||||||
|
# ansible.builtin.lineinfile:
|
||||||
|
# path: /etc/default/locale
|
||||||
|
# regexp: '^LC_TIME='
|
||||||
|
# line: 'LC_TIME=en_DK.UTF-8' # en_DK is the standard trick for English lang + 24h clock
|
||||||
|
# become: yes
|
||||||
|
# tags: [localization]
|
||||||
|
|
||||||
|
#- name: Set system-wide locale and 24h clock
|
||||||
|
# ansible.builtin.command: >
|
||||||
|
# update-locale LANG=en_US.UTF-8 LC_TIME=en_DK.UTF-8
|
||||||
|
# become: yes
|
||||||
|
# changed_when: true
|
||||||
|
|
||||||
|
#- name: Ensure en_US.UTF-8 is generated
|
||||||
|
# ansible.builtin.locale_gen:
|
||||||
|
# name: en_US.UTF-8
|
||||||
|
# state: present
|
||||||
|
# become: yes
|
||||||
|
# tags: [localization]
|
||||||
|
|
||||||
|
- name: Generate required locales
|
||||||
|
ansible.builtin.locale_gen:
|
||||||
|
name: "{{ item }}"
|
||||||
|
state: present
|
||||||
|
become: yes
|
||||||
|
loop:
|
||||||
|
- en_US.UTF-8
|
||||||
|
- en_DK.UTF-8 # We must generate this to use it for the 24h clock
|
||||||
|
tags: [localization]
|
||||||
|
|
||||||
|
|
||||||
|
- name: Force system-wide locale and 24h clock
|
||||||
|
ansible.builtin.command: update-locale LANG=en_US.UTF-8 LC_TIME=en_DK.UTF-8
|
||||||
|
become: yes
|
||||||
|
changed_when: true
|
||||||
|
tags: [localization]
|
||||||
|
|
||||||
|
- name: Flush handlers to apply DNS changes immediately
|
||||||
|
ansible.builtin.meta: flush_handlers
|
||||||
|
|
||||||
|
- name: Wait for DNS to be functional
|
||||||
|
ansible.builtin.command: getent hosts google.com
|
||||||
|
register: dns_check
|
||||||
|
until: dns_check.rc == 0
|
||||||
|
retries: 3
|
||||||
|
delay: 5
|
||||||
|
changed_when: false
|
||||||
|
tags: [identity, network]
|
||||||
|
|
||||||
|
- name: Install baseline packages (Unified list)
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: "{{ common_packages }}"
|
||||||
|
state: present
|
||||||
|
update_cache: yes
|
||||||
|
cache_valid_time: 3600
|
||||||
|
become: yes
|
||||||
|
tags: [packages]
|
||||||
|
|
||||||
|
- name: Install fastfetch (Optional - may not be in legacy repos)
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name:
|
||||||
|
- fastfetch
|
||||||
|
- btm
|
||||||
|
state: present
|
||||||
|
become: yes
|
||||||
|
ignore_errors: yes
|
||||||
|
tags: [packages]
|
||||||
|
|
||||||
|
- name: Configure needrestart for non-interactive automation
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/needrestart/needrestart.conf
|
||||||
|
regexp: '^#?\$nrconf{restart}'
|
||||||
|
line: "$nrconf{restart} = 'a';"
|
||||||
|
become: yes
|
||||||
|
tags: [packages, config]
|
||||||
|
|
||||||
|
- name: Ensure discovery services are enabled and running
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: "{{ item }}"
|
||||||
|
state: started
|
||||||
|
enabled: yes
|
||||||
|
loop:
|
||||||
|
- avahi-daemon
|
||||||
|
- lldpd
|
||||||
|
become: yes
|
||||||
|
tags: [services]
|
||||||
|
|
||||||
|
- name: Include maintenance tasks
|
||||||
|
ansible.builtin.include_tasks: maintenance.yml
|
||||||
|
tags: [maintenance]
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
- name: Managed Lab Maintenance
|
||||||
|
hosts: all_nodes
|
||||||
|
become: true
|
||||||
|
serial: 2 # Update 2 nodes at a time to reduce network/storage strain
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: 1. Update all packages via Nala
|
||||||
|
ansible.builtin.apt:
|
||||||
|
update_cache: yes
|
||||||
|
upgrade: dist
|
||||||
|
autoremove: yes
|
||||||
|
register: apt_res
|
||||||
|
|
||||||
|
- name: 2. Check if a reboot is required
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: /var/run/reboot-required
|
||||||
|
register: reboot_required_file
|
||||||
|
|
||||||
|
- name: 3. Conditional Reboot (Skip Physical Hosts for now)
|
||||||
|
when:
|
||||||
|
- reboot_required_file.stat.exists
|
||||||
|
- inventory_hostname not in groups['physical_iron'] # Handle physical hosts in a separate play
|
||||||
|
ansible.builtin.reboot:
|
||||||
|
msg: "Rebooting {{ inventory_hostname }} after updates"
|
||||||
|
reboot_timeout: 600
|
||||||
|
|
||||||
|
- name: Final Tier - Proxmox Host Maintenance
|
||||||
|
hosts: physical_iron
|
||||||
|
become: true
|
||||||
|
serial: 1 # Reboot physical hosts sequentially to avoid complete cluster downtime
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Check if Host needs reboot
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: /var/run/reboot-required
|
||||||
|
register: host_reboot
|
||||||
|
|
||||||
|
- name: Proxmox Host Reboot Block
|
||||||
|
when: host_reboot.stat.exists
|
||||||
|
block:
|
||||||
|
- name: Graceful shutdown of all VMs/LXCs
|
||||||
|
ansible.builtin.shell: pvesh create /nodes/localhost/stopall
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Reboot the Host
|
||||||
|
ansible.builtin.reboot:
|
||||||
|
msg: "Host maintenance reboot"
|
||||||
|
reboot_timeout: 900
|
||||||
|
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
- name: Infrastructure - Deploy Monitoring Container
|
||||||
|
hosts: lxc_hosts
|
||||||
|
become: true
|
||||||
|
|
||||||
|
pre_tasks:
|
||||||
|
- name: Ensure Host has LXC Python bindings
|
||||||
|
apt:
|
||||||
|
name: python3-lxc
|
||||||
|
state: present
|
||||||
|
update_cache: yes
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Provision Debian 13 LXC
|
||||||
|
community.general.lxc_container:
|
||||||
|
name: monitoring-srv
|
||||||
|
template: debian
|
||||||
|
state: started
|
||||||
|
template_options: --release trixie
|
||||||
|
container_config:
|
||||||
|
- "lxc.net.0.type = veth"
|
||||||
|
- "lxc.net.0.link = lxcbr0" # Adjust to your bridge name
|
||||||
|
- "lxc.start.auto = 1"
|
||||||
|
|
||||||
|
- name: Wait for Network
|
||||||
|
pause:
|
||||||
|
seconds: 10
|
||||||
|
|
||||||
|
- name: Prepare Container for Ansible
|
||||||
|
shell: |
|
||||||
|
lxc-attach -n monitoring-srv -- apt-get update
|
||||||
|
lxc-attach -n monitoring-srv -- apt-get install -y python3 openssh-server
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
- name: Synchronize Host Passwords
|
||||||
|
hosts: all
|
||||||
|
become: yes
|
||||||
|
tasks:
|
||||||
|
- name: Ensure root password is set from Vault
|
||||||
|
ansible.builtin.user:
|
||||||
|
name: root
|
||||||
|
# This takes the text from your vault and hashes it on your Mac
|
||||||
|
password: "{{ vault_root_password | password_hash('sha512') }}"
|
||||||
|
shell: /bin/bash
|
||||||
|
|
||||||
|
- name: Ensure volker password is set from Vault
|
||||||
|
ansible.builtin.user:
|
||||||
|
name: volker
|
||||||
|
password: "{{ vault_root_password | password_hash('sha512') }}"
|
||||||
|
shell: /bin/bash
|
||||||
|
groups: sudo
|
||||||
|
append: yes
|
||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
---
|
||||||
|
- name: Managed Reboot of Lab Infrastructure
|
||||||
|
hosts: all_nodes
|
||||||
|
become: true
|
||||||
|
gather_facts: true
|
||||||
|
serial: 3 # Reboots one host at a time to maintain availability
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Check if reboot is actually required
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: /var/run/reboot-required
|
||||||
|
register: reboot_required_file
|
||||||
|
|
||||||
|
- name: Reboot block
|
||||||
|
when: reboot_required_file.stat.exists
|
||||||
|
block:
|
||||||
|
- name: Handle Proxmox Guests (Endor specific)
|
||||||
|
when: inventory_hostname == 'endor'
|
||||||
|
shell: |
|
||||||
|
# Gracefully stop all running VMs/CTs that aren't set to autostart
|
||||||
|
# or simply rely on Proxmox's built-in shutdown service.
|
||||||
|
# This is a safety check.
|
||||||
|
pvesh create /nodes/localhost/stopall
|
||||||
|
register: stop_all_guests
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Reboot the machine
|
||||||
|
ansible.builtin.reboot:
|
||||||
|
msg: "Reboot initiated by Ansible for kernel updates"
|
||||||
|
connect_timeout: 5
|
||||||
|
reboot_timeout: 600
|
||||||
|
pre_reboot_delay: 10
|
||||||
|
post_reboot_delay: 30
|
||||||
|
test_command: uptime
|
||||||
|
|
||||||
|
- name: Confirm uptime
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "Host {{ inventory_hostname }} is back up and running."
|
||||||
|
|
||||||
|
- name: No reboot needed
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "Host {{ inventory_hostname }} does not require a reboot."
|
||||||
|
when: not reboot_required_file.stat.exists
|
||||||
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
- name: Emergency Password Reset
|
||||||
|
hosts: all
|
||||||
|
become: yes
|
||||||
|
tasks:
|
||||||
|
- name: Force reset root password to something known
|
||||||
|
ansible.builtin.user:
|
||||||
|
name: root
|
||||||
|
# Replace 'TemporaryPassword123' with your desired plain text password
|
||||||
|
password: "{{ 'xxx' | password_hash('sha512', 'mycustomsalt') }}"
|
||||||
|
shell: /bin/bash
|
||||||
|
|
||||||
|
- name: Force reset your main user password
|
||||||
|
ansible.builtin.user:
|
||||||
|
name: volker
|
||||||
|
password: "{{ 'xxx' | password_hash('sha512', 'mycustomsalt') }}"
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
- name: Update Initramfs
|
||||||
|
ansible.builtin.command: update-initramfs -u
|
||||||
|
become: yes
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
---
|
||||||
|
- name: Install matching kernel headers and ZFS tools
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- "linux-headers-{{ ansible_kernel }}"
|
||||||
|
- zfs-dkms
|
||||||
|
- zfsutils-linux
|
||||||
|
state: present
|
||||||
|
update_cache: yes
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: Check if ZFS pool already exists
|
||||||
|
command: zpool list pbs_pool
|
||||||
|
register: zpool_check
|
||||||
|
failed_when: false
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
#- name: Create ZFS RAID10 Pool
|
||||||
|
# shell: |
|
||||||
|
# zpool create -f pbs_pool \
|
||||||
|
# mirror \
|
||||||
|
# ata-TOSHIBA_MG08ACA14TE_61K0A1N5FVJG \
|
||||||
|
# ata-TOSHIBA_MG08ACA14TE_61K0A1TKFVJG \
|
||||||
|
# mirror \
|
||||||
|
# ata-TOSHIBA_MG08ACA14TE_71X0A01QFVJG \
|
||||||
|
# ata-TOSHIBA_MG08ACA14TE_71X0A02VFVJG
|
||||||
|
# args:
|
||||||
|
# chdir: /dev/disk/by-id
|
||||||
|
# become: yes
|
||||||
|
# when: zpool_check.rc != 0
|
||||||
|
|
||||||
|
#- name: Set ZFS properties for the pool
|
||||||
|
# zfs:
|
||||||
|
# name: pbs_pool
|
||||||
|
# state: present
|
||||||
|
# extra_zfs_properties:
|
||||||
|
# compression: lz4
|
||||||
|
# atime: off
|
||||||
|
# xattr: sa
|
||||||
|
# become: yes
|
||||||
|
#
|
||||||
|
#- name: Create dedicated PBS dataset
|
||||||
|
# zfs:
|
||||||
|
# name: pbs_pool/datastore1
|
||||||
|
# state: present
|
||||||
|
# become: yes
|
||||||
|
|
||||||
|
#- name: Limit ZFS ARC cache to 2GB
|
||||||
|
# copy:
|
||||||
|
# dest: /etc/modprobe.d/zfs.conf
|
||||||
|
# content: "options zfs zfs_arc_max=2147483648"
|
||||||
|
# become: yes
|
||||||
|
# notify: Update Initramfs
|
||||||
|
|
||||||
|
|
||||||
|
#### PBS [ProxMoxBackupServer] Starts here
|
||||||
|
|
||||||
|
#### PBS [ProxMoxBackupServer] Starts here
|
||||||
|
|
||||||
|
#### PBS [ProxMoxBackupServer] Starts here
|
||||||
|
#
|
||||||
|
|
||||||
|
#### PBS [ProxMoxBackupServer] Starts here
|
||||||
|
#### PBS [ProxMoxBackupServer] for Trixie ARM64
|
||||||
|
|
||||||
|
- name: Create keyring directory
|
||||||
|
file:
|
||||||
|
path: /etc/apt/keyrings
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: Add PiPBS GPG key (Trixie compatible)
|
||||||
|
get_url:
|
||||||
|
url: https://dexogen.github.io/pipbs/gpg.key
|
||||||
|
dest: /etc/apt/keyrings/pipbs.asc
|
||||||
|
mode: '0644'
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: Add PiPBS Trixie Repository
|
||||||
|
copy:
|
||||||
|
dest: /etc/apt/sources.list.d/pipbs.list
|
||||||
|
content: "deb [arch=arm64 signed-by=/etc/apt/keyrings/pipbs.asc] https://dexogen.github.io/pipbs/ trixie main"
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: Install Proxmox Backup Server and ZFS tools
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- zfs-initramfs
|
||||||
|
- proxmox-backup-server
|
||||||
|
state: present
|
||||||
|
update_cache: yes
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: Ensure PBS has ownership of the datastore
|
||||||
|
file:
|
||||||
|
path: /pbs_pool/datastore1
|
||||||
|
owner: backup
|
||||||
|
group: backup
|
||||||
|
mode: '0770'
|
||||||
|
state: directory
|
||||||
|
become: yes
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Acquire::http::Proxy-Auto-Detect "/usr/local/bin/apt-proxy-detect.sh";
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
sudo rm -vrf /var/cache/apt/archives/*
|
||||||
|
sudo rm /etc/apt/apt.conf.d/00aptproxy
|
||||||
|
#pt-get update -o Acquire::http::No-Cache=True
|
||||||
|
sudo apt-get update -o Acquire::http::No-Cache=True
|
||||||
|
sudo apt-get clean
|
||||||
|
apt-key adv --refresh-keys --keyserver keyserver.ubuntu.com
|
||||||
|
gpg --keyserver keyserver.ubuntu.com --recv-keys 0E98404D386FA1D9
|
||||||
|
gpg --export --armor 0E98404D386FA1D9 | sudo apt-key add -
|
||||||
|
sudo apt update
|
||||||
|
#used this to be distributed via Ansible to remove the Apt cacher and unfuck ssome fucked up apt keys
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
volker ALL=(ALL) NOPASSWD: ALL
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
- name: Restart systemd-resolved
|
||||||
|
ansible.builtin.service: # Changed from 'systemd' to 'service' for compatibility
|
||||||
|
name: systemd-resolved
|
||||||
|
state: restarted
|
||||||
|
ignore_errors: yes # <--- Add this line
|
||||||
|
|
||||||
|
|
||||||
|
- name: Reload NetworkManager
|
||||||
|
systemd:
|
||||||
|
name: NetworkManager
|
||||||
|
state: reloaded
|
||||||
@@ -0,0 +1,300 @@
|
|||||||
|
---
|
||||||
|
- name: Ensure global variables are loaded explicitly
|
||||||
|
ansible.builtin.include_vars:
|
||||||
|
file: "{{ playbook_dir }}/group_vars/all.yml"
|
||||||
|
tags: [always]
|
||||||
|
|
||||||
|
- name: Ensure Proxmox GPG key is present (for Raspberry Pi/PBS)
|
||||||
|
ansible.builtin.get_url:
|
||||||
|
url: https://enterprise.proxmox.com/debian/proxmox-release-trixie.gpg
|
||||||
|
dest: /etc/apt/trusted.gpg.d/proxmox-release-trixie.gpg
|
||||||
|
mode: '0644'
|
||||||
|
become: yes
|
||||||
|
when: ansible_distribution == 'Debian'
|
||||||
|
tags: [setup]
|
||||||
|
|
||||||
|
- name: Set hostname
|
||||||
|
ansible.builtin.hostname:
|
||||||
|
name: "{{ inventory_hostname }}"
|
||||||
|
become: yes
|
||||||
|
tags: [identity]
|
||||||
|
|
||||||
|
- name: Update /etc/hosts for FQDN resolution
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/hosts
|
||||||
|
regexp: '^127\.0\.1\.1'
|
||||||
|
line: "127.0.1.1 {{ inventory_hostname }}.{{ domain_name }} {{ inventory_hostname }}"
|
||||||
|
become: yes
|
||||||
|
tags: [identity]
|
||||||
|
|
||||||
|
- name: Check for NetworkManager
|
||||||
|
ansible.builtin.command: systemctl is-active NetworkManager
|
||||||
|
register: nm_status
|
||||||
|
failed_when: false
|
||||||
|
changed_when: false
|
||||||
|
tags: [identity, network]
|
||||||
|
|
||||||
|
- name: Configure NetworkManager Search Domain (Raspberry Pi/mDNS Style)
|
||||||
|
when:
|
||||||
|
- nm_status.rc == 0
|
||||||
|
- ansible_virtualization_type != 'lxc'
|
||||||
|
tags: [identity, network]
|
||||||
|
block:
|
||||||
|
- name: Get active connection name
|
||||||
|
ansible.builtin.shell: "nmcli -t -f NAME connection show --active | head -n 1"
|
||||||
|
register: active_conn
|
||||||
|
changed_when: false
|
||||||
|
- name: Apply search domain via nmcli
|
||||||
|
ansible.builtin.command: "nmcli connection modify '{{ active_conn.stdout }}' ipv4.dns-search '{{ domain_name }}'"
|
||||||
|
when: active_conn.stdout != ""
|
||||||
|
notify: Reload NetworkManager
|
||||||
|
|
||||||
|
- name: Configure systemd-resolved Search Domain (Vanilla Debian Style)
|
||||||
|
ansible.builtin.ini_file:
|
||||||
|
path: /etc/systemd/resolved.conf
|
||||||
|
section: Resolve
|
||||||
|
option: Domains
|
||||||
|
value: "{{ domain_name }}"
|
||||||
|
become: yes
|
||||||
|
notify: Restart systemd-resolved
|
||||||
|
when:
|
||||||
|
- nm_status.rc != 0
|
||||||
|
- ansible_virtualization_type != 'lxc'
|
||||||
|
tags: [identity, network]
|
||||||
|
|
||||||
|
- name: Ensure the terminal is always functional
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/profile
|
||||||
|
line: 'export TERM=xterm-256color'
|
||||||
|
state: present
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: Set system timezone
|
||||||
|
community.general.timezone:
|
||||||
|
name: Europe/Berlin
|
||||||
|
become: yes
|
||||||
|
tags: [localization]
|
||||||
|
|
||||||
|
- name: Generate required locales
|
||||||
|
ansible.builtin.locale_gen:
|
||||||
|
name: "{{ item }}"
|
||||||
|
state: present
|
||||||
|
become: yes
|
||||||
|
loop:
|
||||||
|
- en_US.UTF-8
|
||||||
|
- en_DK.UTF-8
|
||||||
|
tags: [localization]
|
||||||
|
|
||||||
|
- name: Force system-wide locale and 24h clock
|
||||||
|
ansible.builtin.command: update-locale LANG=en_US.UTF-8 LC_TIME=en_DK.UTF-8
|
||||||
|
become: yes
|
||||||
|
changed_when: true
|
||||||
|
tags: [localization]
|
||||||
|
|
||||||
|
- name: Flush handlers to apply DNS changes immediately
|
||||||
|
ansible.builtin.meta: flush_handlers
|
||||||
|
|
||||||
|
- name: Wait for DNS to be functional
|
||||||
|
ansible.builtin.command: getent hosts google.com
|
||||||
|
register: dns_check
|
||||||
|
until: dns_check.rc == 0
|
||||||
|
retries: 3
|
||||||
|
delay: 5
|
||||||
|
changed_when: false
|
||||||
|
when: ansible_virtualization_type != 'lxc'
|
||||||
|
tags: [identity, network]
|
||||||
|
|
||||||
|
# --- REINE PACKET-TASKS OHNE SECURITY ---
|
||||||
|
|
||||||
|
- name: Install baseline packages (Unified list from group_vars)
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: "{{ item }}"
|
||||||
|
state: present
|
||||||
|
update_cache: yes
|
||||||
|
cache_valid_time: 3600
|
||||||
|
loop: "{{ common_packages }}"
|
||||||
|
when: not (item == 'sudo' and 'yunohost_servers' in group_names)
|
||||||
|
become: yes
|
||||||
|
ignore_errors: yes
|
||||||
|
tags: [packages, common]
|
||||||
|
|
||||||
|
- name: Install modern packages like fastfetch (Debian 13+ only)
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: "{{ modern_os_packages | default(['fastfetch']) }}"
|
||||||
|
state: present
|
||||||
|
become: yes
|
||||||
|
when:
|
||||||
|
- ansible_os_family == "Debian"
|
||||||
|
- ansible_distribution_major_version | int >= 13
|
||||||
|
ignore_errors: yes
|
||||||
|
tags: [packages, common]
|
||||||
|
|
||||||
|
- name: Install QEMU Guest Agent (VMs only - NOT on LXC or Physical Iron)
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: qemu-guest-agent
|
||||||
|
state: present
|
||||||
|
become: yes
|
||||||
|
when:
|
||||||
|
- "'proxmox_vms' in group_names"
|
||||||
|
- "'lxc_containers' not in group_names"
|
||||||
|
- "'physical_iron' not in group_names"
|
||||||
|
tags: [packages, proxmox]
|
||||||
|
|
||||||
|
# --- SYSTEM-EINSTELLUNGEN & DIENSTE ---
|
||||||
|
|
||||||
|
- name: Configure needrestart for non-interactive automation
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/needrestart/needrestart.conf
|
||||||
|
regexp: '^#?\$nrconf{restart}'
|
||||||
|
line: "$nrconf{restart} = 'a';"
|
||||||
|
become: yes
|
||||||
|
tags: [packages, config]
|
||||||
|
|
||||||
|
- name: Ensure discovery services are enabled and running
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: "{{ item }}"
|
||||||
|
state: started
|
||||||
|
enabled: yes
|
||||||
|
loop:
|
||||||
|
- avahi-daemon
|
||||||
|
- lldpd
|
||||||
|
become: yes
|
||||||
|
tags: [services]
|
||||||
|
|
||||||
|
- name: Include maintenance tasks
|
||||||
|
ansible.builtin.include_tasks: maintenance.yml
|
||||||
|
tags: [maintenance]
|
||||||
|
|
||||||
|
- name: Ensure console getty is running (for Proxmox WebUI access)
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: getty@tty1.service
|
||||||
|
state: started
|
||||||
|
enabled: yes
|
||||||
|
become: yes
|
||||||
|
tags: [services, setup]
|
||||||
|
|
||||||
|
- name: Ensure Node Exporter is running for monitoring
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: prometheus-node-exporter
|
||||||
|
state: started
|
||||||
|
enabled: yes
|
||||||
|
become: yes
|
||||||
|
tags: [monitoring, services]
|
||||||
|
|
||||||
|
- name: Fix Vim mouse behavior for easy copy-paste
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /etc/vim/vimrc.local
|
||||||
|
content: |
|
||||||
|
set mouse=
|
||||||
|
syntax on
|
||||||
|
set number
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0644'
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
# --- GHOSTTY TERMINFO SHIZZLE ---
|
||||||
|
|
||||||
|
- name: Create Ghostty terminfo source file on remote
|
||||||
|
ansible.builtin.copy:
|
||||||
|
content: |
|
||||||
|
{% raw %}
|
||||||
|
xterm-ghostty|ghostty|Ghostty,
|
||||||
|
am, bce, ccc, hs, km, mc5i, mir, msgr, npc, xenl, AX, Su, Tc, XT, fullkbd,
|
||||||
|
colors#256, cols#80, it#8, lines#24, pairs#32767,
|
||||||
|
acsc=++\,\,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
|
||||||
|
bel=^G, blink=\E[5m, bold=\E[1m, cbt=\E[Z, civis=\E[?25l,
|
||||||
|
clear=\E[H\E[2J, cnorm=\E[?12l\E[?25h, cr=^M,
|
||||||
|
csr=\E[%i%p1%d;%p2%dr, cub=\E[%p1%dD, cub1=^H,
|
||||||
|
cud=\E[%p1%dB, cud1=^J, cuf=\E[%p1%dC, cuf1=\E[C,
|
||||||
|
cup=\E[%i%p1%d;%p2%dH, cuu=\E[%p1%dA, cuu1=\E[A,
|
||||||
|
cvvis=\E[?12;25h, dch=\E[%p1%dP, dch1=\E[P, dim=\E[2m,
|
||||||
|
dl=\E[%p1%dM, dl1=\E[M, dsl=\E]2;\007, ech=\E[%p1%dX,
|
||||||
|
ed=\E[J, el=\E[K, el1=\E[1K, flash=\E[?5h$<100/>\E[?5l,
|
||||||
|
fsl=^G, home=\E[H, hpa=\E[%i%p1%dG, ht=^I, hts=\EH,
|
||||||
|
ich=\E[%p1%d@, ich1=\E[@, il=\E[%p1%dL, il1=\E[L, ind=^J,
|
||||||
|
indn=\E[%p1%dS,
|
||||||
|
initc=\E]4;%p1%d;rgb\:%p2%{255}%*%{1000}%/%2.2X/%p3%{255}%*%{1000}%/%2.2X/%p4%{255}%*%{1000}%/%2.2X\E\\,
|
||||||
|
invis=\E[8m, kDC=\E[3;2~, kEND=\E[1;2F, kHOM=\E[1;2H,
|
||||||
|
kIC=\E[2;2~, kLFT=\E[1;2D, kNXT=\E[6;2~, kPRV=\E[5;2~,
|
||||||
|
kRIT=\E[1;2C, kbs=\177, kcbt=\E[Z, kcub1=\EOD, kcud1=\EOB,
|
||||||
|
kcuf1=\EOC, kcuu1=\EOA, kdch1=\E[3~, kend=\EOF, kent=\EOM,
|
||||||
|
kf1=\EOP, kf10=\E[21~, kf11=\E[23~, kf12=\E[24~,
|
||||||
|
kf13=\E[1;2P, kf14=\E[1;2Q, kf15=\E[1;2R, kf16=\E[1;2S,
|
||||||
|
kf17=\E[15;2~, kf18=\E[17;2~, kf19=\E[18;2~, kf2=\EOQ,
|
||||||
|
kf20=\E[19;2~, kf21=\E[20;2~, kf22=\E[21;2~,
|
||||||
|
kf23=\E[23;2~, kf24=\E[24;2~, kf25=\E[1;5P, kf26=\E[1;5Q,
|
||||||
|
kf27=\E[1;5R, kf28=\E[1;5S, kf29=\E[15;5~, kf3=\EOR,
|
||||||
|
kf30=\E[17;5~, kf31=\E[18;5~, kf32=\E[19;5~,
|
||||||
|
kf33=\E[20;5~, kf34=\E[21;5~, kf35=\E[23;5~,
|
||||||
|
kf36=\E[24;5~, kf37=\E[1;6P, kf38=\E[1;6Q, kf39=\E[1;6R,
|
||||||
|
kf4=\EOS, kf40=\E[1;6S, kf41=\E[15;6~, kf42=\E[17;6~,
|
||||||
|
kf43=\E[18;6~, kf44=\E[19;6~, kf45=\E[20;6~,
|
||||||
|
kf46=\E[21;6~, kf47=\E[23;6~, kf48=\E[24;6~,
|
||||||
|
kf49=\E[1;3P, kf5=\E[15~, kf50=\E[1;3Q, kf51=\E[1;3R,
|
||||||
|
kf52=\E[1;3S, kf53=\E[15;3~, kf54=\E[17;3~,
|
||||||
|
kf55=\E[18;3~, kf56=\E[19;3~, kf57=\E[20;3~,
|
||||||
|
kf58=\E[21;3~, kf59=\E[23;3~, kf6=\E[17~, kf60=\E[24;3~,
|
||||||
|
kf61=\E[1;4P, kf62=\E[1;4Q, kf63=\E[1;4R, kf7=\E[18~,
|
||||||
|
kf8=\E[19~, kf9=\E[20~, khome=\EOH, kich1=\E[2~,
|
||||||
|
kind=\E[1;2B, kmous=\E[<, knp=\E[6~, kpp=\E[5~,
|
||||||
|
kri=\E[1;2A, oc=\E]104\007, op=\E[39;49m, rc=\E8,
|
||||||
|
rep=%p1%c\E[%p2%{1}%-%db, rev=\E[7m, ri=\EM,
|
||||||
|
rin=\E[%p1%dT, ritm=\E[23m, rmacs=\E(B, rmam=\E[?7l,
|
||||||
|
rmcup=\E[?1049l, rmir=\E[4l, rmkx=\E[?1l\E>, rmso=\E[27m,
|
||||||
|
rmul=\E[24m, rs1=\E]\E\\\Ec, sc=\E7,
|
||||||
|
setab=\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m,
|
||||||
|
setaf=\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m,
|
||||||
|
sgr=%?%p9%t\E(0%e\E(B%;\E[0%?%p6%t;1%;%?%p5%t;2%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m,
|
||||||
|
sgr0=\E(B\E[m, sitm=\E[3m, smacs=\E(0, smam=\E[?7h,
|
||||||
|
smcup=\E[?1049h, smir=\E[4h, smkx=\E[?1h\E=, smso=\E[7m,
|
||||||
|
smul=\E[4m, tbc=\E[3g, tsl=\E]2;, u6=\E[%i%d;%dR, u7=\E[6n,
|
||||||
|
u8=\E[?%[;0123456789]c, u9=\E[c, vpa=\E[%i%p1%dd,
|
||||||
|
BD=\E[?2004l, BE=\E[?2004h, Clmg=\E[s,
|
||||||
|
Cmg=\E[%i%p1%d;%p2%ds, Dsmg=\E[?69l, E3=\E[3J,
|
||||||
|
Enmg=\E[?69h, Ms=\E]52;%p1%s;%p2%s\007, PE=\E[201~,
|
||||||
|
PS=\E[200~, RV=\E[>c, Se=\E[2 q,
|
||||||
|
Setulc=\E[58\:2\:\:%p1%{65536}%/%d\:%p1%{256}%/%{255}%&%d\:%p1%{255}%&%d%;m,
|
||||||
|
Smulx=\E[4\:%p1%dm, Ss=\E[%p1%d q,
|
||||||
|
Sync=\E[?2026%?%p1%{1}%-%tl%eh%;,
|
||||||
|
XM=\E[?1006;1000%?%p1%{1}%=%th%el%;, XR=\E[>0q,
|
||||||
|
fd=\E[?1004l, fe=\E[?1004h, kDC3=\E[3;3~, kDC4=\E[3;4~,
|
||||||
|
kDC5=\E[3;5~, kDC6=\E[3;6~, kDC7=\E[3;7~, kDN=\E[1;2B,
|
||||||
|
kDN3=\E[1;3B, kDN4=\E[1;4B, kDN5=\E[1;5B, kDN6=\E[1;6B,
|
||||||
|
kDN7=\E[1;7B, kEND3=\E[1;3F, kEND4=\E[1;4F,
|
||||||
|
kEND5=\E[1;5F, kEND6=\E[1;6F, kEND7=\E[1;7F,
|
||||||
|
kHOM3=\E[1;3H, kHOM4=\E[1;4H, kHOM5=\E[1;5H,
|
||||||
|
kHOM6=\E[1;6H, kHOM7=\E[1;7H, kIC3=\E[2;3~, kIC4=\E[2;4~,
|
||||||
|
kIC5=\E[2;5~, kIC6=\E[2;6~, kIC7=\E[2;7~, kLFT3=\E[1;3D,
|
||||||
|
kLFT4=\E[1;4D, kLFT5=\E[1;5D, kLFT6=\E[1;6D,
|
||||||
|
kLFT7=\E[1;7D, kNXT3=\E[6;3~, kNXT4=\E[6;4~,
|
||||||
|
kNXT5=\E[6;5~, kNXT6=\E[6;6~, kNXT7=\E[6;7~,
|
||||||
|
kPRV3=\E[5;3~, kPRV4=\E[5;4~, kPRV5=\E[5;5~,
|
||||||
|
kPRV6=\E[5;6~, kPRV7=\E[5;7~, kRIT3=\E[1;3C,
|
||||||
|
kRIT4=\E[1;4C, kRIT5=\E[1;5C, kRIT6=\E[1;6C,
|
||||||
|
kRIT7=\E[1;7C, kUP=\E[1;2A, kUP3=\E[1;3A, kUP4=\E[1;4A,
|
||||||
|
kUP5=\E[1;5A, kUP6=\E[1;6A, kUP7=\E[1;7A, kxIN=\E[I,
|
||||||
|
kxOUT=\E[O, rmxx=\E[29m, rv=\E\\[[0-9]+;[0-9]+;[0-9]+c,
|
||||||
|
setrgbb=\E[48\:2\:%p1%d\:%p2%d\:%p3%dm,
|
||||||
|
setrgbf=\E[38\:2\:%p1%d\:%p2%d\:%p3%dm, smxx=\E[9m,
|
||||||
|
xm=\E[<%i%p3%d;%p1%d;%p2%d;%?%p4%tM%em%;,
|
||||||
|
xr=\EP>\\|[ -~]+a\E\\,
|
||||||
|
{% endraw %}
|
||||||
|
dest: /tmp/xterm-ghostty
|
||||||
|
mode: '0644'
|
||||||
|
ignore_errors: yes
|
||||||
|
tags: [common, terminal]
|
||||||
|
|
||||||
|
- name: Optimize terminfo for Ghostty terminal
|
||||||
|
ansible.builtin.command: tic -x /tmp/xterm-ghostty
|
||||||
|
become: yes
|
||||||
|
changed_when: false
|
||||||
|
ignore_errors: yes
|
||||||
|
tags: [common, terminal]
|
||||||
|
|
||||||
|
- name: Clean up temporary Ghostty terminfo file
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /tmp/xterm-ghostty
|
||||||
|
state: absent
|
||||||
|
ignore_errors: yes
|
||||||
|
tags: [common, terminal]
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
- name: Install base packages
|
||||||
|
package:
|
||||||
|
name: [vim, git, curl, avahi-daemon]
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Set hostname
|
||||||
|
hostname:
|
||||||
|
name: "{{ inventory_hostname }}"
|
||||||
|
|
||||||
|
- name: Update /etc/hosts for FQDN resolution
|
||||||
|
lineinfile:
|
||||||
|
path: /etc/hosts
|
||||||
|
regexp: '^127\.0\.1\.1'
|
||||||
|
line: "127.0.1.1 {{ inventory_hostname }}.{{ domain_name }} {{ inventory_hostname }}"
|
||||||
|
|
||||||
|
- name: Check for NetworkManager
|
||||||
|
command: systemctl is-active NetworkManager
|
||||||
|
register: nm_status
|
||||||
|
ignore_errors: yes
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Configure NetworkManager Search Domain (Raspberry Pi Style)
|
||||||
|
block:
|
||||||
|
- name: Get active connection name
|
||||||
|
shell: "nmcli -t -f NAME connection show --active | head -n 1"
|
||||||
|
register: active_conn
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Apply search domain via nmcli
|
||||||
|
command: "nmcli connection modify '{{ active_conn.stdout }}' ipv4.dns-search '{{ domain_name }}'"
|
||||||
|
when: active_conn.stdout != ""
|
||||||
|
notify: Reload NetworkManager
|
||||||
|
when: nm_status.rc == 0
|
||||||
|
|
||||||
|
- name: Configure systemd-resolved Search Domain (Vanilla Debian Style)
|
||||||
|
ini_file:
|
||||||
|
path: /etc/systemd/resolved.conf
|
||||||
|
section: Resolve
|
||||||
|
option: Domains
|
||||||
|
value: "{{ domain_name }}"
|
||||||
|
notify: Restart systemd-resolved
|
||||||
|
when: nm_status.rc != 0
|
||||||
|
- name: Flush handlers to apply DNS changes immediately
|
||||||
|
meta: flush_handlers
|
||||||
|
|
||||||
|
- name: Wait for DNS to be functional
|
||||||
|
command: getent hosts google.com
|
||||||
|
register: dns_check
|
||||||
|
until: dns_check.rc == 0
|
||||||
|
retries: 3
|
||||||
|
delay: 5
|
||||||
|
|
||||||
|
- name: Install merged baseline packages
|
||||||
|
apt:
|
||||||
|
name: "{{ common_packages }}"
|
||||||
|
state: present
|
||||||
|
update_cache: yes
|
||||||
|
cache_valid_time: 3600
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: Configure needrestart for non-interactive automation
|
||||||
|
lineinfile:
|
||||||
|
path: /etc/needrestart/needrestart.conf
|
||||||
|
regexp: '^#?\$nrconf{restart}'
|
||||||
|
line: "$nrconf{restart} = 'a';"
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: Ensure discovery services are enabled and running
|
||||||
|
service:
|
||||||
|
name: "{{ item }}"
|
||||||
|
state: started
|
||||||
|
enabled: yes
|
||||||
|
loop:
|
||||||
|
- avahi-daemon
|
||||||
|
- lldpd
|
||||||
|
become: yes
|
||||||
|
- name: Include maintenance tasks
|
||||||
|
include_tasks: maintenance.yml
|
||||||
@@ -0,0 +1,200 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
# FIX: InfluxData GPG Key Rotation (Required for Debian Trixie/sqv)
|
||||||
|
- name: InfluxData GPG Key Repair
|
||||||
|
become: true
|
||||||
|
tags: [maintenance, setup]
|
||||||
|
block:
|
||||||
|
- name: Remove known bad/expired Influx list files
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "/etc/apt/sources.list.d/{{ item }}"
|
||||||
|
state: absent
|
||||||
|
loop:
|
||||||
|
- repos_influxdata_com_debian.list
|
||||||
|
- influxdb.list
|
||||||
|
|
||||||
|
- name: Download the 2026-valid InfluxData archive key
|
||||||
|
ansible.builtin.get_url:
|
||||||
|
url: https://repos.influxdata.com/influxdata-archive.key
|
||||||
|
dest: /tmp/influxdata-archive.key
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
- name: Dearmor key for sqv (Sequoia-PGP) compatibility
|
||||||
|
ansible.builtin.shell: |
|
||||||
|
cat /tmp/influxdata-archive.key | gpg --dearmor > /usr/share/keyrings/influxdata-archive.gpg
|
||||||
|
args:
|
||||||
|
creates: /usr/share/keyrings/influxdata-archive.gpg
|
||||||
|
|
||||||
|
- name: Write clean InfluxData source list with signed-by flag
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /etc/apt/sources.list.d/influxdata.list
|
||||||
|
content: "deb [signed-by=/usr/share/keyrings/influxdata-archive.gpg] https://repos.influxdata.com/debian stable main"
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
|
||||||
|
- name: Ensure Proxmox GPG key is present (for Raspberry Pi/PBS)
|
||||||
|
ansible.builtin.get_url:
|
||||||
|
url: https://enterprise.proxmox.com/debian/proxmox-release-trixie.gpg
|
||||||
|
dest: /etc/apt/trusted.gpg.d/proxmox-release-trixie.gpg
|
||||||
|
mode: '0644'
|
||||||
|
become: yes
|
||||||
|
when: ansible_distribution == 'Debian'
|
||||||
|
tags: [setup]
|
||||||
|
|
||||||
|
- name: Set hostname
|
||||||
|
ansible.builtin.hostname:
|
||||||
|
name: "{{ inventory_hostname }}"
|
||||||
|
become: yes
|
||||||
|
tags: [identity]
|
||||||
|
|
||||||
|
- name: Update /etc/hosts for FQDN resolution
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/hosts
|
||||||
|
regexp: '^127\.0\.1\.1'
|
||||||
|
line: "127.0.1.1 {{ inventory_hostname }}.{{ domain_name }} {{ inventory_hostname }}"
|
||||||
|
become: yes
|
||||||
|
tags: [identity]
|
||||||
|
|
||||||
|
- name: Check for NetworkManager
|
||||||
|
ansible.builtin.command: systemctl is-active NetworkManager
|
||||||
|
register: nm_status
|
||||||
|
failed_when: false
|
||||||
|
changed_when: false
|
||||||
|
tags: [identity, network]
|
||||||
|
|
||||||
|
- name: Configure NetworkManager Search Domain (Raspberry Pi/mDNS Style)
|
||||||
|
when: nm_status.rc == 0
|
||||||
|
tags: [identity, network]
|
||||||
|
block:
|
||||||
|
- name: Get active connection name
|
||||||
|
ansible.builtin.shell: "nmcli -t -f NAME connection show --active | head -n 1"
|
||||||
|
register: active_conn
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Apply search domain via nmcli
|
||||||
|
ansible.builtin.command: "nmcli connection modify '{{ active_conn.stdout }}' ipv4.dns-search '{{ domain_name }}'"
|
||||||
|
when: active_conn.stdout != ""
|
||||||
|
notify: Reload NetworkManager
|
||||||
|
|
||||||
|
- name: Configure systemd-resolved Search Domain (Vanilla Debian Style)
|
||||||
|
ansible.builtin.ini_file:
|
||||||
|
path: /etc/systemd/resolved.conf
|
||||||
|
section: Resolve
|
||||||
|
option: Domains
|
||||||
|
value: "{{ domain_name }}"
|
||||||
|
become: yes
|
||||||
|
notify: Restart systemd-resolved
|
||||||
|
when: nm_status.rc != 0
|
||||||
|
tags: [identity, network]
|
||||||
|
|
||||||
|
- name: Ensure the terminal is always functional
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/profile
|
||||||
|
line: 'export TERM=xterm-256color'
|
||||||
|
state: present
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: Set system timezone
|
||||||
|
community.general.timezone:
|
||||||
|
name: Europe/Berlin
|
||||||
|
become: yes
|
||||||
|
tags: [localization]
|
||||||
|
|
||||||
|
- name: Generate required locales
|
||||||
|
ansible.builtin.locale_gen:
|
||||||
|
name: "{{ item }}"
|
||||||
|
state: present
|
||||||
|
become: yes
|
||||||
|
loop:
|
||||||
|
- en_US.UTF-8
|
||||||
|
- en_DK.UTF-8 # Required for the 24h clock format
|
||||||
|
tags: [localization]
|
||||||
|
|
||||||
|
- name: Force system-wide locale and 24h clock
|
||||||
|
ansible.builtin.command: update-locale LANG=en_US.UTF-8 LC_TIME=en_DK.UTF-8
|
||||||
|
become: yes
|
||||||
|
changed_when: true
|
||||||
|
tags: [localization]
|
||||||
|
|
||||||
|
- name: Flush handlers to apply DNS changes immediately
|
||||||
|
ansible.builtin.meta: flush_handlers
|
||||||
|
|
||||||
|
- name: Wait for DNS to be functional
|
||||||
|
ansible.builtin.command: getent hosts google.com
|
||||||
|
register: dns_check
|
||||||
|
until: dns_check.rc == 0
|
||||||
|
retries: 3
|
||||||
|
delay: 5
|
||||||
|
changed_when: false
|
||||||
|
tags: [identity, network]
|
||||||
|
|
||||||
|
- name: Install baseline packages (Unified list)
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: "{{ common_packages }}"
|
||||||
|
state: present
|
||||||
|
update_cache: yes
|
||||||
|
cache_valid_time: 3600
|
||||||
|
become: yes
|
||||||
|
tags: [packages]
|
||||||
|
|
||||||
|
- name: Install fastfetch (Optional - may not be in legacy repos)
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name:
|
||||||
|
- fastfetch
|
||||||
|
- btm
|
||||||
|
state: present
|
||||||
|
become: yes
|
||||||
|
ignore_errors: yes
|
||||||
|
tags: [packages]
|
||||||
|
|
||||||
|
- name: Configure needrestart for non-interactive automation
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/needrestart/needrestart.conf
|
||||||
|
regexp: '^#?\$nrconf{restart}'
|
||||||
|
line: "$nrconf{restart} = 'a';"
|
||||||
|
become: yes
|
||||||
|
tags: [packages, config]
|
||||||
|
|
||||||
|
- name: Ensure discovery services are enabled and running
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: "{{ item }}"
|
||||||
|
state: started
|
||||||
|
enabled: yes
|
||||||
|
loop:
|
||||||
|
- avahi-daemon
|
||||||
|
- lldpd
|
||||||
|
become: yes
|
||||||
|
tags: [services]
|
||||||
|
|
||||||
|
- name: Include maintenance tasks
|
||||||
|
ansible.builtin.include_tasks: maintenance.yml
|
||||||
|
tags: [maintenance]
|
||||||
|
|
||||||
|
- name: Ensure console getty is running (for Proxmox WebUI access)
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: getty@tty1.service
|
||||||
|
state: started
|
||||||
|
enabled: yes
|
||||||
|
become: yes
|
||||||
|
tags: [services, setup]
|
||||||
|
|
||||||
|
- name: Ensure Node Exporter is running for monitoring
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: prometheus-node-exporter
|
||||||
|
state: started
|
||||||
|
enabled: yes
|
||||||
|
become: yes
|
||||||
|
tags: [monitoring, services]
|
||||||
|
|
||||||
|
|
||||||
|
- name: Fix Vim mouse behavior for easy copy-paste
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /etc/vim/vimrc.local
|
||||||
|
content: |
|
||||||
|
set mouse=
|
||||||
|
syntax on
|
||||||
|
set number
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0644'
|
||||||
|
become: yes
|
||||||
@@ -0,0 +1,290 @@
|
|||||||
|
---
|
||||||
|
- name: Ensure Proxmox GPG key is present (for Raspberry Pi/PBS)
|
||||||
|
ansible.builtin.get_url:
|
||||||
|
url: https://enterprise.proxmox.com/debian/proxmox-release-trixie.gpg
|
||||||
|
dest: /etc/apt/trusted.gpg.d/proxmox-release-trixie.gpg
|
||||||
|
mode: '0644'
|
||||||
|
become: yes
|
||||||
|
when: ansible_distribution == 'Debian'
|
||||||
|
tags: [setup]
|
||||||
|
|
||||||
|
- name: Set hostname
|
||||||
|
ansible.builtin.hostname:
|
||||||
|
name: "{{ inventory_hostname }}"
|
||||||
|
become: yes
|
||||||
|
tags: [identity]
|
||||||
|
|
||||||
|
- name: Update /etc/hosts for FQDN resolution
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/hosts
|
||||||
|
regexp: '^127\.0\.1\.1'
|
||||||
|
line: "127.0.1.1 {{ inventory_hostname }}.{{ domain_name }} {{ inventory_hostname }}"
|
||||||
|
become: yes
|
||||||
|
tags: [identity]
|
||||||
|
|
||||||
|
- name: Check for NetworkManager
|
||||||
|
ansible.builtin.command: systemctl is-active NetworkManager
|
||||||
|
register: nm_status
|
||||||
|
failed_when: false
|
||||||
|
changed_when: false
|
||||||
|
tags: [identity, network]
|
||||||
|
|
||||||
|
- name: Configure NetworkManager Search Domain (Raspberry Pi/mDNS Style)
|
||||||
|
when:
|
||||||
|
- nm_status.rc == 0
|
||||||
|
- ansible_virtualization_type != 'lxc' # <-- NEU: Überspringe LXC
|
||||||
|
tags: [identity, network]
|
||||||
|
block:
|
||||||
|
- name: Get active connection name
|
||||||
|
ansible.builtin.shell: "nmcli -t -f NAME connection show --active | head -n 1"
|
||||||
|
register: active_conn
|
||||||
|
changed_when: false
|
||||||
|
- name: Apply search domain via nmcli
|
||||||
|
ansible.builtin.command: "nmcli connection modify '{{ active_conn.stdout }}' ipv4.dns-search '{{ domain_name }}'"
|
||||||
|
when: active_conn.stdout != ""
|
||||||
|
notify: Reload NetworkManager
|
||||||
|
|
||||||
|
- name: Configure systemd-resolved Search Domain (Vanilla Debian Style)
|
||||||
|
ansible.builtin.ini_file:
|
||||||
|
path: /etc/systemd/resolved.conf
|
||||||
|
section: Resolve
|
||||||
|
option: Domains
|
||||||
|
value: "{{ domain_name }}"
|
||||||
|
become: yes
|
||||||
|
notify: Restart systemd-resolved
|
||||||
|
when:
|
||||||
|
- nm_status.rc != 0
|
||||||
|
- ansible_virtualization_type != 'lxc' # <-- NEU: Überspringe LXC
|
||||||
|
tags: [identity, network]
|
||||||
|
|
||||||
|
- name: Ensure the terminal is always functional
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/profile
|
||||||
|
line: 'export TERM=xterm-256color'
|
||||||
|
state: present
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: Set system timezone
|
||||||
|
community.general.timezone:
|
||||||
|
name: Europe/Berlin
|
||||||
|
become: yes
|
||||||
|
tags: [localization]
|
||||||
|
|
||||||
|
- name: Generate required locales
|
||||||
|
ansible.builtin.locale_gen:
|
||||||
|
name: "{{ item }}"
|
||||||
|
state: present
|
||||||
|
become: yes
|
||||||
|
loop:
|
||||||
|
- en_US.UTF-8
|
||||||
|
- en_DK.UTF-8 # Required for the 24h clock format
|
||||||
|
tags: [localization]
|
||||||
|
|
||||||
|
- name: Force system-wide locale and 24h clock
|
||||||
|
ansible.builtin.command: update-locale LANG=en_US.UTF-8 LC_TIME=en_DK.UTF-8
|
||||||
|
become: yes
|
||||||
|
changed_when: true
|
||||||
|
tags: [localization]
|
||||||
|
|
||||||
|
- name: Flush handlers to apply DNS changes immediately
|
||||||
|
ansible.builtin.meta: flush_handlers
|
||||||
|
|
||||||
|
- name: Wait for DNS to be functional
|
||||||
|
ansible.builtin.command: getent hosts google.com
|
||||||
|
register: dns_check
|
||||||
|
until: dns_check.rc == 0
|
||||||
|
retries: 3
|
||||||
|
delay: 5
|
||||||
|
changed_when: false
|
||||||
|
when: ansible_virtualization_type != 'lxc' # <-- NEU: Überspringe LXC
|
||||||
|
tags: [identity, network]
|
||||||
|
|
||||||
|
# --- REINE PACKET-TASKS OHNE SECURITY ---
|
||||||
|
|
||||||
|
- name: Install baseline packages (Unified list from group_vars)
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: "{{ common_packages }}"
|
||||||
|
state: present
|
||||||
|
update_cache: yes
|
||||||
|
cache_valid_time: 3600
|
||||||
|
become: yes
|
||||||
|
tags: [packages]
|
||||||
|
|
||||||
|
- name: Install modern packages like fastfetch (Debian 13+ only)
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: "{{ modern_os_packages | default(['fastfetch']) }}"
|
||||||
|
state: present
|
||||||
|
become: yes
|
||||||
|
when:
|
||||||
|
- ansible_os_family == "Debian"
|
||||||
|
- ansible_distribution_major_version | int >= 13
|
||||||
|
tags: [packages]
|
||||||
|
|
||||||
|
- name: Install QEMU Guest Agent (VMs only - NOT on LXC or Physical Iron)
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: qemu-guest-agent
|
||||||
|
state: present
|
||||||
|
become: yes
|
||||||
|
when:
|
||||||
|
- "'proxmox_vms' in group_names"
|
||||||
|
- "'lxc_containers' not in group_names"
|
||||||
|
- "'physical_iron' not in group_names"
|
||||||
|
tags: [packages, proxmox]
|
||||||
|
|
||||||
|
# --- SYSTEM-EINSTELLUNGEN & DIENSTE ---
|
||||||
|
|
||||||
|
- name: Configure needrestart for non-interactive automation
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/needrestart/needrestart.conf
|
||||||
|
regexp: '^#?\$nrconf{restart}'
|
||||||
|
line: "$nrconf{restart} = 'a';"
|
||||||
|
become: yes
|
||||||
|
tags: [packages, config]
|
||||||
|
|
||||||
|
- name: Ensure discovery services are enabled and running
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: "{{ item }}"
|
||||||
|
state: started
|
||||||
|
enabled: yes
|
||||||
|
loop:
|
||||||
|
- avahi-daemon
|
||||||
|
- lldpd
|
||||||
|
become: yes
|
||||||
|
tags: [services]
|
||||||
|
|
||||||
|
- name: Include maintenance tasks
|
||||||
|
ansible.builtin.include_tasks: maintenance.yml
|
||||||
|
tags: [maintenance]
|
||||||
|
|
||||||
|
- name: Ensure console getty is running (for Proxmox WebUI access)
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: getty@tty1.service
|
||||||
|
state: started
|
||||||
|
enabled: yes
|
||||||
|
become: yes
|
||||||
|
tags: [services, setup]
|
||||||
|
|
||||||
|
- name: Ensure Node Exporter is running for monitoring
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: prometheus-node-exporter
|
||||||
|
state: started
|
||||||
|
enabled: yes
|
||||||
|
become: yes
|
||||||
|
tags: [monitoring, services]
|
||||||
|
|
||||||
|
- name: Fix Vim mouse behavior for easy copy-paste
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /etc/vim/vimrc.local
|
||||||
|
content: |
|
||||||
|
set mouse=
|
||||||
|
syntax on
|
||||||
|
set number
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0644'
|
||||||
|
become: yes
|
||||||
|
### ghosty shit shizzle
|
||||||
|
|
||||||
|
- name: Create Ghostty terminfo source file on remote
|
||||||
|
ansible.builtin.copy:
|
||||||
|
content: |
|
||||||
|
{% raw %}
|
||||||
|
xterm-ghostty|ghostty|Ghostty,
|
||||||
|
am, bce, ccc, hs, km, mc5i, mir, msgr, npc, xenl, AX, Su, Tc, XT, fullkbd,
|
||||||
|
colors#256, cols#80, it#8, lines#24, pairs#32767,
|
||||||
|
acsc=++\,\,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
|
||||||
|
bel=^G, blink=\E[5m, bold=\E[1m, cbt=\E[Z, civis=\E[?25l,
|
||||||
|
clear=\E[H\E[2J, cnorm=\E[?12l\E[?25h, cr=^M,
|
||||||
|
csr=\E[%i%p1%d;%p2%dr, cub=\E[%p1%dD, cub1=^H,
|
||||||
|
cud=\E[%p1%dB, cud1=^J, cuf=\E[%p1%dC, cuf1=\E[C,
|
||||||
|
cup=\E[%i%p1%d;%p2%dH, cuu=\E[%p1%dA, cuu1=\E[A,
|
||||||
|
cvvis=\E[?12;25h, dch=\E[%p1%dP, dch1=\E[P, dim=\E[2m,
|
||||||
|
dl=\E[%p1%dM, dl1=\E[M, dsl=\E]2;\007, ech=\E[%p1%dX,
|
||||||
|
ed=\E[J, el=\E[K, el1=\E[1K, flash=\E[?5h$<100/>\E[?5l,
|
||||||
|
fsl=^G, home=\E[H, hpa=\E[%i%p1%dG, ht=^I, hts=\EH,
|
||||||
|
ich=\E[%p1%d@, ich1=\E[@, il=\E[%p1%dL, il1=\E[L, ind=^J,
|
||||||
|
indn=\E[%p1%dS,
|
||||||
|
initc=\E]4;%p1%d;rgb\:%p2%{255}%*%{1000}%/%2.2X/%p3%{255}%*%{1000}%/%2.2X/%p4%{255}%*%{1000}%/%2.2X\E\\,
|
||||||
|
invis=\E[8m, kDC=\E[3;2~, kEND=\E[1;2F, kHOM=\E[1;2H,
|
||||||
|
kIC=\E[2;2~, kLFT=\E[1;2D, kNXT=\E[6;2~, kPRV=\E[5;2~,
|
||||||
|
kRIT=\E[1;2C, kbs=\177, kcbt=\E[Z, kcub1=\EOD, kcud1=\EOB,
|
||||||
|
kcuf1=\EOC, kcuu1=\EOA, kdch1=\E[3~, kend=\EOF, kent=\EOM,
|
||||||
|
kf1=\EOP, kf10=\E[21~, kf11=\E[23~, kf12=\E[24~,
|
||||||
|
kf13=\E[1;2P, kf14=\E[1;2Q, kf15=\E[1;2R, kf16=\E[1;2S,
|
||||||
|
kf17=\E[15;2~, kf18=\E[17;2~, kf19=\E[18;2~, kf2=\EOQ,
|
||||||
|
kf20=\E[19;2~, kf21=\E[20;2~, kf22=\E[21;2~,
|
||||||
|
kf23=\E[23;2~, kf24=\E[24;2~, kf25=\E[1;5P, kf26=\E[1;5Q,
|
||||||
|
kf27=\E[1;5R, kf28=\E[1;5S, kf29=\E[15;5~, kf3=\EOR,
|
||||||
|
kf30=\E[17;5~, kf31=\E[18;5~, kf32=\E[19;5~,
|
||||||
|
kf33=\E[20;5~, kf34=\E[21;5~, kf35=\E[23;5~,
|
||||||
|
kf36=\E[24;5~, kf37=\E[1;6P, kf38=\E[1;6Q, kf39=\E[1;6R,
|
||||||
|
kf4=\EOS, kf40=\E[1;6S, kf41=\E[15;6~, kf42=\E[17;6~,
|
||||||
|
kf43=\E[18;6~, kf44=\E[19;6~, kf45=\E[20;6~,
|
||||||
|
kf46=\E[21;6~, kf47=\E[23;6~, kf48=\E[24;6~,
|
||||||
|
kf49=\E[1;3P, kf5=\E[15~, kf50=\E[1;3Q, kf51=\E[1;3R,
|
||||||
|
kf52=\E[1;3S, kf53=\E[15;3~, kf54=\E[17;3~,
|
||||||
|
kf55=\E[18;3~, kf56=\E[19;3~, kf57=\E[20;3~,
|
||||||
|
kf58=\E[21;3~, kf59=\E[23;3~, kf6=\E[17~, kf60=\E[24;3~,
|
||||||
|
kf61=\E[1;4P, kf62=\E[1;4Q, kf63=\E[1;4R, kf7=\E[18~,
|
||||||
|
kf8=\E[19~, kf9=\E[20~, khome=\EOH, kich1=\E[2~,
|
||||||
|
kind=\E[1;2B, kmous=\E[<, knp=\E[6~, kpp=\E[5~,
|
||||||
|
kri=\E[1;2A, oc=\E]104\007, op=\E[39;49m, rc=\E8,
|
||||||
|
rep=%p1%c\E[%p2%{1}%-%db, rev=\E[7m, ri=\EM,
|
||||||
|
rin=\E[%p1%dT, ritm=\E[23m, rmacs=\E(B, rmam=\E[?7l,
|
||||||
|
rmcup=\E[?1049l, rmir=\E[4l, rmkx=\E[?1l\E>, rmso=\E[27m,
|
||||||
|
rmul=\E[24m, rs1=\E]\E\\\Ec, sc=\E7,
|
||||||
|
setab=\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m,
|
||||||
|
setaf=\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m,
|
||||||
|
sgr=%?%p9%t\E(0%e\E(B%;\E[0%?%p6%t;1%;%?%p5%t;2%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m,
|
||||||
|
sgr0=\E(B\E[m, sitm=\E[3m, smacs=\E(0, smam=\E[?7h,
|
||||||
|
smcup=\E[?1049h, smir=\E[4h, smkx=\E[?1h\E=, smso=\E[7m,
|
||||||
|
smul=\E[4m, tbc=\E[3g, tsl=\E]2;, u6=\E[%i%d;%dR, u7=\E[6n,
|
||||||
|
u8=\E[?%[;0123456789]c, u9=\E[c, vpa=\E[%i%p1%dd,
|
||||||
|
BD=\E[?2004l, BE=\E[?2004h, Clmg=\E[s,
|
||||||
|
Cmg=\E[%i%p1%d;%p2%ds, Dsmg=\E[?69l, E3=\E[3J,
|
||||||
|
Enmg=\E[?69h, Ms=\E]52;%p1%s;%p2%s\007, PE=\E[201~,
|
||||||
|
PS=\E[200~, RV=\E[>c, Se=\E[2 q,
|
||||||
|
Setulc=\E[58\:2\:\:%p1%{65536}%/%d\:%p1%{256}%/%{255}%&%d\:%p1%{255}%&%d%;m,
|
||||||
|
Smulx=\E[4\:%p1%dm, Ss=\E[%p1%d q,
|
||||||
|
Sync=\E[?2026%?%p1%{1}%-%tl%eh%;,
|
||||||
|
XM=\E[?1006;1000%?%p1%{1}%=%th%el%;, XR=\E[>0q,
|
||||||
|
fd=\E[?1004l, fe=\E[?1004h, kDC3=\E[3;3~, kDC4=\E[3;4~,
|
||||||
|
kDC5=\E[3;5~, kDC6=\E[3;6~, kDC7=\E[3;7~, kDN=\E[1;2B,
|
||||||
|
kDN3=\E[1;3B, kDN4=\E[1;4B, kDN5=\E[1;5B, kDN6=\E[1;6B,
|
||||||
|
kDN7=\E[1;7B, kEND3=\E[1;3F, kEND4=\E[1;4F,
|
||||||
|
kEND5=\E[1;5F, kEND6=\E[1;6F, kEND7=\E[1;7F,
|
||||||
|
kHOM3=\E[1;3H, kHOM4=\E[1;4H, kHOM5=\E[1;5H,
|
||||||
|
kHOM6=\E[1;6H, kHOM7=\E[1;7H, kIC3=\E[2;3~, kIC4=\E[2;4~,
|
||||||
|
kIC5=\E[2;5~, kIC6=\E[2;6~, kIC7=\E[2;7~, kLFT3=\E[1;3D,
|
||||||
|
kLFT4=\E[1;4D, kLFT5=\E[1;5D, kLFT6=\E[1;6D,
|
||||||
|
kLFT7=\E[1;7D, kNXT3=\E[6;3~, kNXT4=\E[6;4~,
|
||||||
|
kNXT5=\E[6;5~, kNXT6=\E[6;6~, kNXT7=\E[6;7~,
|
||||||
|
kPRV3=\E[5;3~, kPRV4=\E[5;4~, kPRV5=\E[5;5~,
|
||||||
|
kPRV6=\E[5;6~, kPRV7=\E[5;7~, kRIT3=\E[1;3C,
|
||||||
|
kRIT4=\E[1;4C, kRIT5=\E[1;5C, kRIT6=\E[1;6C,
|
||||||
|
kRIT7=\E[1;7C, kUP=\E[1;2A, kUP3=\E[1;3A, kUP4=\E[1;4A,
|
||||||
|
kUP5=\E[1;5A, kUP6=\E[1;6A, kUP7=\E[1;7A, kxIN=\E[I,
|
||||||
|
kxOUT=\E[O, rmxx=\E[29m, rv=\E\\[[0-9]+;[0-9]+;[0-9]+c,
|
||||||
|
setrgbb=\E[48\:2\:%p1%d\:%p2%d\:%p3%dm,
|
||||||
|
setrgbf=\E[38\:2\:%p1%d\:%p2%d\:%p3%dm, smxx=\E[9m,
|
||||||
|
xm=\E[<%i%p3%d;%p1%d;%p2%d;%?%p4%tM%em%;,
|
||||||
|
xr=\EP>\\|[ -~]+a\E\\,
|
||||||
|
{% endraw %}
|
||||||
|
dest: /tmp/xterm-ghostty
|
||||||
|
mode: '0644'
|
||||||
|
ignore_errors: yes
|
||||||
|
tags: [common, terminal]
|
||||||
|
|
||||||
|
- name: Optimize terminfo for Ghostty terminal
|
||||||
|
ansible.builtin.command: tic -x /tmp/xterm-ghostty
|
||||||
|
become: yes
|
||||||
|
changed_when: false
|
||||||
|
ignore_errors: yes
|
||||||
|
tags: [common, terminal]
|
||||||
|
|
||||||
|
- name: Clean up temporary Ghostty terminfo file
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /tmp/xterm-ghostty
|
||||||
|
state: absent
|
||||||
|
ignore_errors: yes
|
||||||
|
tags: [common, terminal]
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
---
|
||||||
|
- name: Update and upgrade apt packages
|
||||||
|
become: true
|
||||||
|
ansible.builtin.apt:
|
||||||
|
update_cache: yes
|
||||||
|
upgrade: dist
|
||||||
|
autoremove: yes
|
||||||
|
purge: yes
|
||||||
|
tags: [maintenance, upgrade]
|
||||||
|
|
||||||
|
- name: Check if a reboot is required
|
||||||
|
become: true
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: /var/run/reboot-required
|
||||||
|
register: reboot_required_file
|
||||||
|
tags: [maintenance]
|
||||||
|
|
||||||
|
- name: Notify about pending reboot
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "Host {{ inventory_hostname }} requires a reboot."
|
||||||
|
when: reboot_required_file.stat.exists
|
||||||
|
tags: [maintenance]
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
- name: Restart Samba
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: smbd
|
||||||
|
state: restarted
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
- name: Install Samba packages
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name:
|
||||||
|
- samba
|
||||||
|
- samba-common-bin
|
||||||
|
- smbclient
|
||||||
|
state: present
|
||||||
|
update_cache: yes
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: Ensure Samba shared directories exist
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item.path }}"
|
||||||
|
state: directory
|
||||||
|
loop: "{{ samba_shares }}"
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: Deploy Samba configuration from template
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: smb.conf.template
|
||||||
|
dest: /etc/samba/smb.conf
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0644'
|
||||||
|
become: yes
|
||||||
|
notify: Restart Samba
|
||||||
|
|
||||||
|
|
||||||
|
#- name: Ensure Samba shared directories exist
|
||||||
|
# ansible.builtin.file:
|
||||||
|
# path: "{{ item.path }}"
|
||||||
|
# state: directory
|
||||||
|
# loop: "{{ samba_shares }}"
|
||||||
|
# owner: "{{ item.force_user | default('volker') }}"
|
||||||
|
# group: "{{ item.group | default('volker') }}"
|
||||||
|
# mode: "{{ item.mode | default('0775') }}"
|
||||||
|
# loop: "{{ samba_shares }}"
|
||||||
|
# ignore_errors: yes # <-- Das fängt den chown-Fehler bei externen Mounts ab
|
||||||
|
|
||||||
|
#- name: Ensure Samba services are started and enabled
|
||||||
|
# ansible.builtin.service:
|
||||||
|
# name: "{{ item }}"
|
||||||
|
# state: started
|
||||||
|
# enabled: yes
|
||||||
|
# loop:
|
||||||
|
# - smbd
|
||||||
|
# - nmbd
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
- name: Install and Configure Samba
|
||||||
|
hosts: samba_servers
|
||||||
|
become: yes
|
||||||
|
tasks:
|
||||||
|
- name: Install Samba
|
||||||
|
package:
|
||||||
|
name: samba
|
||||||
|
state: present
|
||||||
|
- name: Ensure NFS utilities are installed.
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- nfs-common
|
||||||
|
- nfs-kernel-server
|
||||||
|
state: present
|
||||||
|
- name: Configure smb.conf
|
||||||
|
template:
|
||||||
|
src: smb.conf.template
|
||||||
|
dest: /etc/samba/smb.conf
|
||||||
|
notify: restart samba
|
||||||
|
|
||||||
|
# handlers:
|
||||||
|
# - name: restart samba
|
||||||
|
# service:
|
||||||
|
# name: smbd
|
||||||
|
# state: restarted
|
||||||
|
# state: present
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
[global]
|
||||||
|
workgroup = WORKGROUP
|
||||||
|
netbios name = {{ inventory_hostname }}
|
||||||
|
server string = %h server (Samba, Ubuntu)
|
||||||
|
log file = /var/log/samba/log.%m
|
||||||
|
max log size = 1000
|
||||||
|
logging = file
|
||||||
|
panic action = /usr/share/samba/panic-action %d
|
||||||
|
server role = standalone server
|
||||||
|
obey pam restrictions = yes
|
||||||
|
unix password sync = yes
|
||||||
|
passwd program = /usr/bin/passwd %u
|
||||||
|
passwd chat = *Enter\snew\s*\spassword:* %n\n *Retype\snew\s*\spassword:* %n\n *password\supdated\ssuccessfully* .
|
||||||
|
pam password change = yes
|
||||||
|
map to guest = bad user
|
||||||
|
usershare allow guests = yes
|
||||||
|
# --- macOS Optimization (Fruit) ---
|
||||||
|
vfs objects = fruit streams_xattr recycle
|
||||||
|
fruit:model = MacPro7,1@ECOLOR=226,226,224
|
||||||
|
fruit:metadata = stream
|
||||||
|
fruit:veto_appledouble = no
|
||||||
|
fruit:posix_rename = yes
|
||||||
|
|
||||||
|
# --- Recycle Bin Logic ---
|
||||||
|
recycle:touch = yes
|
||||||
|
recycle:keeptree = yes
|
||||||
|
recycle:versions = yes
|
||||||
|
|
||||||
|
# Dynamic Shares Loop
|
||||||
|
{% for share in samba_shares %}
|
||||||
|
[{{ share.name }}]
|
||||||
|
path = {{ share.path }}
|
||||||
|
browseable = {{ share.browseable | default('yes') }}
|
||||||
|
read only = {{ share.read_only | default('no') }}
|
||||||
|
guest ok = {{ share.guest_ok | default('yes') }}
|
||||||
|
{% if share.force_user is defined %}
|
||||||
|
force user = {{ share.force_user }}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
- name: Restart Prometheus
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: prometheus
|
||||||
|
state: restarted
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
---
|
||||||
|
# 1. This part runs on EVERY node
|
||||||
|
- name: Install Node Exporter (Agent)
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: prometheus-node-exporter
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Ensure Node Exporter is running
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: prometheus-node-exporter
|
||||||
|
state: started
|
||||||
|
enabled: yes
|
||||||
|
|
||||||
|
# 2. This part ONLY runs on the monitor node
|
||||||
|
- name: Install Monitoring Server Stack
|
||||||
|
when: inventory_hostname == 'monitor'
|
||||||
|
block:
|
||||||
|
- name: Add Grafana GPG key
|
||||||
|
ansible.builtin.get_url:
|
||||||
|
url: https://apt.grafana.com/gpg.key
|
||||||
|
dest: /usr/share/keyrings/grafana.gpg
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
- name: Add Grafana Repo
|
||||||
|
ansible.builtin.apt_repository:
|
||||||
|
repo: "deb [signed-by=/usr/share/keyrings/grafana.gpg] https://apt.grafana.com stable main"
|
||||||
|
state: present
|
||||||
|
- name: Ensure prometheus system user exists
|
||||||
|
ansible.builtin.user:
|
||||||
|
name: prometheus
|
||||||
|
shell: /bin/false
|
||||||
|
system: yes
|
||||||
|
create_home: no
|
||||||
|
when: inventory_hostname == 'monitor'
|
||||||
|
|
||||||
|
- name: Ensure prometheus data directory has correct permissions
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /var/lib/prometheus
|
||||||
|
state: directory
|
||||||
|
owner: prometheus
|
||||||
|
group: prometheus
|
||||||
|
mode: '0755'
|
||||||
|
when: inventory_hostname == 'monitor'
|
||||||
|
|
||||||
|
|
||||||
|
- name: Install Server Packages
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name:
|
||||||
|
- influxdb
|
||||||
|
- grafana
|
||||||
|
- prometheus # The server engine
|
||||||
|
state: present
|
||||||
|
update_cache: yes
|
||||||
|
|
||||||
|
- name: Deploy Prometheus configuration from template
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: prometheus.yml.j2
|
||||||
|
dest: /etc/prometheus/prometheus.yml
|
||||||
|
owner: prometheus
|
||||||
|
group: prometheus
|
||||||
|
mode: '0644'
|
||||||
|
notify: Restart Prometheus
|
||||||
|
|
||||||
|
- name: Ensure Server Services are running
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: "{{ item }}"
|
||||||
|
state: started
|
||||||
|
enabled: yes
|
||||||
|
loop:
|
||||||
|
- influxdb
|
||||||
|
- grafana-server
|
||||||
|
- prometheus
|
||||||
|
|
||||||
|
- name: Configure InfluxDB UDP listener for Proxmox
|
||||||
|
ansible.builtin.blockinfile:
|
||||||
|
path: /etc/influxdb/influxdb.conf
|
||||||
|
insertafter: '\[\[udp\]\]'
|
||||||
|
block: |
|
||||||
|
enabled = true
|
||||||
|
bind-address = ":8089"
|
||||||
|
database = "proxmox"
|
||||||
|
batch-size = 1000
|
||||||
|
batch-timeout = "1s"
|
||||||
|
when: inventory_hostname == 'monitor'
|
||||||
|
notify: Restart Influxdb
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
global:
|
||||||
|
scrape_interval: 15s
|
||||||
|
|
||||||
|
scrape_configs:
|
||||||
|
- job_name: 'prometheus'
|
||||||
|
static_configs:
|
||||||
|
- targets: ['localhost:9090']
|
||||||
|
|
||||||
|
- job_name: 'lab_nodes'
|
||||||
|
static_configs:
|
||||||
|
- targets:
|
||||||
|
{% for host in groups['all_nodes'] %}
|
||||||
|
- '{{ hostvars[host].ansible_host }}:9100'
|
||||||
|
{% endfor %}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
- name: Restart Caddy
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: caddy
|
||||||
|
state: restarted
|
||||||
|
become: yes
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
---
|
||||||
|
- name: Ensure old Cloudsmith repository artifact is removed
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /etc/apt/sources.list.d/caddy-stable.list
|
||||||
|
state: absent
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: Install Caddy server package from official Debian repositories
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: caddy
|
||||||
|
state: present
|
||||||
|
update_cache: yes
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: Deploy Caddyfile configuration from template
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: Caddyfile.j2
|
||||||
|
dest: /etc/caddy/Caddyfile
|
||||||
|
owner: caddy
|
||||||
|
group: caddy
|
||||||
|
mode: '0644'
|
||||||
|
become: yes
|
||||||
|
notify: Restart Caddy
|
||||||
|
|
||||||
|
- name: Ensure Caddy service is enabled and running
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: caddy
|
||||||
|
state: started
|
||||||
|
enabled: yes
|
||||||
|
become: yes
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
# --- Yunohost: bumb ---
|
||||||
|
gh120.de, *.gh120.de {
|
||||||
|
reverse_proxy 192.168.112.46:443 {
|
||||||
|
transport http {
|
||||||
|
tls_insecure_skip_verify
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Yunohost: rohan ---
|
||||||
|
wks20.de, *.wks20.de {
|
||||||
|
reverse_proxy 192.168.112.42:443 {
|
||||||
|
transport http {
|
||||||
|
tls_insecure_skip_verify
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# SUBDOMAINS FÜR GH120.DE (YunoHost 'bumb' - 192.168.112.46)
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
ha.gh120.de {
|
||||||
|
reverse_proxy https://192.168.112.46 {
|
||||||
|
transport http {
|
||||||
|
tls_insecure_skip_verify
|
||||||
|
}
|
||||||
|
header_up Web-Socket-Allowed true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nc.gh120.de {
|
||||||
|
reverse_proxy https://192.168.112.46 {
|
||||||
|
transport http {
|
||||||
|
tls_insecure_skip_verify
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
img.gh120.de {
|
||||||
|
request_body {
|
||||||
|
max_size 10GB
|
||||||
|
}
|
||||||
|
reverse_proxy https://192.168.112.46 {
|
||||||
|
transport http {
|
||||||
|
tls_insecure_skip_verify
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
docs.gh120.de {
|
||||||
|
reverse_proxy https://192.168.112.46 {
|
||||||
|
transport http {
|
||||||
|
tls_insecure_skip_verify
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
paper.gh120.de {
|
||||||
|
reverse_proxy https://192.168.112.46 {
|
||||||
|
transport http {
|
||||||
|
tls_insecure_skip_verify
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# SUBDOMAINS FÜR WKS20.DE (YunoHost 'rohan' - 192.168.112.42)
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
links.wks20.de {
|
||||||
|
reverse_proxy https://192.168.112.42 {
|
||||||
|
transport http {
|
||||||
|
tls_insecure_skip_verify
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mantis.wks20.de {
|
||||||
|
reverse_proxy https://192.168.112.42 {
|
||||||
|
transport http {
|
||||||
|
tls_insecure_skip_verify
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nc.wks20.de {
|
||||||
|
reverse_proxy https://192.168.112.42 {
|
||||||
|
transport http {
|
||||||
|
tls_insecure_skip_verify
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pics.wks20.de {
|
||||||
|
request_body {
|
||||||
|
max_size 10GB
|
||||||
|
}
|
||||||
|
reverse_proxy https://192.168.112.42 {
|
||||||
|
transport http {
|
||||||
|
tls_insecure_skip_verify
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
roundc.wks20.de {
|
||||||
|
reverse_proxy https://192.168.112.42 {
|
||||||
|
transport http {
|
||||||
|
tls_insecure_skip_verify
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tea.wks20.de {
|
||||||
|
reverse_proxy https://192.168.112.42 {
|
||||||
|
transport http {
|
||||||
|
tls_insecure_skip_verify
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
warden.wks20.de {
|
||||||
|
reverse_proxy https://192.168.112.42 {
|
||||||
|
transport http {
|
||||||
|
tls_insecure_skip_verify
|
||||||
|
}
|
||||||
|
header_up Web-Socket-Allowed true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wiki.wks20.de {
|
||||||
|
reverse_proxy https://192.168.112.42 {
|
||||||
|
transport http {
|
||||||
|
tls_insecure_skip_verify
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# --- Future Optional (Auskommentiert) ---
|
||||||
|
# jellyfin.gh120.de {
|
||||||
|
# reverse_proxy 192.168.123.114:8096
|
||||||
|
#
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCqKm6tSG73CudRxZkUnR/hcwKQnvSfkQM/Gq1gR6wswu4kcthHZ+YCxzRFIJmTR1+C0UXy8yRVtwprz31plFbHvU3Om913MGaN1oadunYOkKD8OmAtCtht9H+5wC5HtjwuhNf/MH1K727ecNUSH10DYovzXkOD6byJukfkvbU6CVKxWAI6W9PXTLOPRyUoy3TX0GEBascayneqHBFfPGpICnR76X9Ydi2avfgmNiGtTMzKkn1mNqm3a4eHCfde8XUBtqlxdMnO/pMlgMh14XoBSD5T+U3OqIUvMOiU3ZKlcq4W46wtPX1Im6iqfgFutwT1YqQ8UNY06urO41nH6d5rVfSA1BS7Fonho2xK5lQ3aqapn2+o9goXTIQ1avoOHyWS0j+W8m5BEL8Prvr+eqjTCivh5g4rKVe2SebKzZU89oZSEkV9Mj69qhS1g3LnyJds+oskl04CdRXrn5KSyxXP9X4m0EYYfbzWMAPRZ6SsltAOw9w4hwZtwIKSl2+bMQAqQmRojDof4FgK+DCQfdcThhrmknGtGiL1v3tJuCmmiikoKis5qOVBmVJOhJaSOTKSIhx3oTVVfCgzlEnGE0M7gUk1+Qh30p4TahsbyfcWg5v3+0vdIVgAWIdW0Kp0s9R0mU4qKeIuZ9ejHCmaGcQe2ZolQZc5UrTwMBb1PaqPQQ== key von macbook fuer rogueone
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFhNTFIBVTfsFDiO5oKdTWxOkk9jrpnqYma6DFNkCROq strider-mackbook-2023-ed
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC+5jrJHgRNSsZICWTRFppyVyyn1SfnboEa4/bwCd9yad34e0f3CRu5EGlVzKUZAar7D1EWxjeFEeJF1hmaY0iJGbnmzf2BT8FHIhiJqa/EyiKlrVY+rHsvkzP26XOe8xlZdh5MAEsKt4/6jnvWN8H+pctvQzOfynh8+9HdgU/df7M7YKrFd9sSToFx0dZfI+3eF0OfLrjYp2fKGVK/SiiyUBJE96h39IK13grMxlwQ2vv3p4zSu6ADINJipa1sedu8earq0t4dsxvy/0F7wwbfkMgek0Q0eN/gT31pM/m1NXpc7Qk1E2M8YcaFIUAbYchqoZT8wsn4/MxjbY835226RCIOPrEL+CmKzF904S3zUqIU2BJ42IGGBtCtM9eoRS3BMkYFLKY4vEH0bDTu9KSwBdLdc/1JYQZi5NPZSW0rH1OeKntJACmUczCK2NXAJraGm374eT/JRJkSQxFLolKZRo6duhAdkPcvGZeGTMSgcLguZ7ayZuz3Q730JqMtVV0jKpXbRjAM5kBqflc31580xgrG6J6gG/cTh9XvC4VF/vP8yP44HGODNtJeiTVBdowltsFA+xUPspJa8fFysCcSL0dmKjr+wlfMZgjiuEAJ3Ejm9m7VsVjeeWdlfRXVDUIrInsEYz+9lADrZvSom9cZGksuP581m3h4ncnLyFU9uw== key von macbook fuer goldeneye
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDX9hQGGErj6YUhq5KN934JLZdD4R8lqFlNOSbcY4vWFZp7F/l9zntGaozbzY9X+0WH2qLubrcdWXpWXf3mJPw/gjd+1DAHn/1BkWjgOccmiaM5CQc1SXLs5wZIzhgXuzg+OwGry7XXtAOGdjjAB+c0cDC6bz5o53Y2hiprG5+Y7AuAa7rJxs6AT+EM/gzWsuwofzdEbnnEeQn874gBXOb3IS4GNZL5NNcb1lqocnkmhsQnTXJIGbqkBtzWmWwcS5/GGWhaqFz+Ugv2VUcstgrz7JvtGA5WPr3hCiB+y4QRBiKHrYy/zjWn+ESGk7cYjnhiHdIlRJXeVLkWJlHIr4hN1ajuetx4wS6pg2molZxEwZfTzhDxMHWocVNUHm1UZMAxxQ3VpEq6nvrUM7ppVQicl1R+zgHEeHa9fRUSLq/fBaIg5y4VZCXK7p61O6ms6pK0QoNFcGaSZ9bqYoY0ouPxfNPTMAw5yLu1pFmFC/9+MEB1d/66mdG5x8UdLma2qGRChcVKr1gLqzIEtx69x/0hFKUne9KssInxy+BC55tjpkmbb3euAeuzRIKYtUHz/9XbEUEpjvofnXawtz2FEEddtI/eCtBc65nPP21f/or1ngT6I7gC+Ha9brvK/AmlM3OOx6tvUg1StRwQj9qFdT5FpFbN+cuWnf2/LWf8A5ik7w== key von macbook fuer LXC-Container
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIATdXmHXS8dGIsVa5zmAtjkWRMka/CNcIEeiFX8vru1 sentinel-automation
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
---
|
||||||
|
- name: Ensure the administrative user exists
|
||||||
|
ansible.builtin.user:
|
||||||
|
name: volker
|
||||||
|
shell: /bin/bash
|
||||||
|
groups: sudo
|
||||||
|
append: yes
|
||||||
|
become: yes # Added this to prevent permission denied errors
|
||||||
|
tags: [security, always]
|
||||||
|
|
||||||
|
- name: Allow root SSH login
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/ssh/sshd_config
|
||||||
|
regexp: '^#?PermitRootLogin'
|
||||||
|
line: 'PermitRootLogin yes'
|
||||||
|
become: yes
|
||||||
|
notify: Restart SSH
|
||||||
|
tags: [security, ssh]
|
||||||
|
|
||||||
|
- name: Apply global user security policy
|
||||||
|
ansible.builtin.user:
|
||||||
|
name: "{{ item.name }}"
|
||||||
|
password: "{{ vault_root_password | password_hash('sha512') }}"
|
||||||
|
shell: /bin/bash
|
||||||
|
groups: "{{ item.groups | default(omit) }}"
|
||||||
|
become: yes # <--- Added this for safety
|
||||||
|
loop:
|
||||||
|
- { name: 'root' }
|
||||||
|
- { name: 'volker', groups: 'sudo' }
|
||||||
|
|
||||||
|
#- name: Sync passwords for administrative users
|
||||||
|
# ansible.builtin.user:
|
||||||
|
# name: "{{ item }}"
|
||||||
|
# password: "{{ root_password_hash }}"
|
||||||
|
# become: yes
|
||||||
|
# loop:
|
||||||
|
# - root
|
||||||
|
# - volker
|
||||||
|
# tags: [security]
|
||||||
|
|
||||||
|
- name: Ensure SSH keys are synchronized for both users
|
||||||
|
ansible.posix.authorized_key:
|
||||||
|
user: "{{ item }}"
|
||||||
|
state: present
|
||||||
|
key: "{{ lookup('file', 'authorized_keys_volker') }}"
|
||||||
|
become: yes
|
||||||
|
loop:
|
||||||
|
- root
|
||||||
|
- volker
|
||||||
|
tags: [security, ssh]
|
||||||
|
|
||||||
|
- name: Passwordless sudo for volker
|
||||||
|
ansible.builtin.copy:
|
||||||
|
content: "volker ALL=(ALL) NOPASSWD:ALL"
|
||||||
|
dest: /etc/sudoers.d/volker
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0440'
|
||||||
|
validate: /usr/sbin/visudo -cf %s
|
||||||
|
become: yes
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
---
|
||||||
|
- name: Get distribution version
|
||||||
|
setup:
|
||||||
|
filter: ansible_distribution*
|
||||||
|
- name: Skip if not Debian 12
|
||||||
|
meta: end_host
|
||||||
|
when: ansible_distribution != 'Debian' or ansible_distribution_major_version != '12'
|
||||||
|
- name: apt clean
|
||||||
|
apt:
|
||||||
|
clean: yes
|
||||||
|
become: yes
|
||||||
|
- name: Get filesystem facts
|
||||||
|
setup:
|
||||||
|
filter: ansible_mounts
|
||||||
|
- name: Fail if free space on / is below 5 GiB
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- item.size_available > (5 * 1024 * 1024 * 1024)
|
||||||
|
fail_msg: "Free disk space on {{ item.mount }} is below 5 GiB"
|
||||||
|
loop: "{{ ansible_mounts }}"
|
||||||
|
when: item.mount == "/"
|
||||||
|
- name: All apt packages up to date
|
||||||
|
apt:
|
||||||
|
upgrade: dist
|
||||||
|
update_cache: yes
|
||||||
|
become: yes
|
||||||
|
- name: apt autoremove
|
||||||
|
apt:
|
||||||
|
autoremove: yes
|
||||||
|
become: yes
|
||||||
|
- name: apt clean
|
||||||
|
apt:
|
||||||
|
clean: yes
|
||||||
|
become: yes
|
||||||
|
- name: Check if reboot required
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: /run/reboot-required
|
||||||
|
get_checksum: no
|
||||||
|
register: reboot_required_file
|
||||||
|
- name: Reboot if required
|
||||||
|
ansible.builtin.reboot:
|
||||||
|
msg: "Reboot initiated by Ansible"
|
||||||
|
connect_timeout: 5
|
||||||
|
reboot_timeout: 600
|
||||||
|
pre_reboot_delay: 0
|
||||||
|
post_reboot_delay: 60
|
||||||
|
test_command: whoami
|
||||||
|
when: reboot_required_file.stat.exists
|
||||||
|
become: true
|
||||||
|
- name: Switch OS from bookworm to trixie
|
||||||
|
ansible.builtin.replace:
|
||||||
|
path: /etc/apt/sources.list
|
||||||
|
regexp: 'bookworm'
|
||||||
|
replace: 'trixie'
|
||||||
|
become: yes
|
||||||
|
- name: Find all 3rd-party repos
|
||||||
|
ansible.builtin.find:
|
||||||
|
paths: /etc/apt/sources.list.d
|
||||||
|
patterns: '*'
|
||||||
|
recurse: no
|
||||||
|
register: third_party_repos
|
||||||
|
- name: Switch 3rd-party repos from bookworm to trixie
|
||||||
|
ansible.builtin.replace:
|
||||||
|
path: "{{ item.path }}"
|
||||||
|
regexp: 'bookworm'
|
||||||
|
replace: 'trixie'
|
||||||
|
loop: "{{ third_party_repos.files }}"
|
||||||
|
loop_control:
|
||||||
|
label: "{{ item.path }}"
|
||||||
|
become: yes
|
||||||
|
- name: Use apt to move to trixie
|
||||||
|
apt:
|
||||||
|
upgrade: dist
|
||||||
|
update_cache: yes
|
||||||
|
become: yes
|
||||||
|
- name: Get distribution version
|
||||||
|
setup:
|
||||||
|
filter: ansible_distribution*
|
||||||
|
- name: Fail if not Debian 13
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- ansible_distribution_major_version == '13'
|
||||||
|
fail_msg: "Upgrade to Debian 13 failed"
|
||||||
|
- name: apt autoremove
|
||||||
|
apt:
|
||||||
|
autoremove: yes
|
||||||
|
become: yes
|
||||||
|
- name: apt clean
|
||||||
|
apt:
|
||||||
|
clean: yes
|
||||||
|
become: yes
|
||||||
|
- name: Reboot on trixie
|
||||||
|
ansible.builtin.reboot:
|
||||||
|
msg: "Reboot initiated by Ansible"
|
||||||
|
connect_timeout: 5
|
||||||
|
reboot_timeout: 600
|
||||||
|
pre_reboot_delay: 0
|
||||||
|
post_reboot_delay: 60
|
||||||
|
test_command: whoami
|
||||||
|
become: yes
|
||||||
|
- name: Modernize apt sources
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: apt -y modernize-sources
|
||||||
|
become: yes
|
||||||
|
- name: Pause for 5 minutes for staggered upgrades
|
||||||
|
pause:
|
||||||
|
minutes: 5
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
" Basic Quality of Life
|
||||||
|
set nocompatible
|
||||||
|
filetype plugin indent on
|
||||||
|
syntax on
|
||||||
|
set number
|
||||||
|
set relativenumber " Great for jumping lines in code
|
||||||
|
set mouse=a
|
||||||
|
set clipboard=unnamedplus
|
||||||
|
|
||||||
|
" Ghostty / Modern Terminal Compatibility
|
||||||
|
if exists('+termguicolors')
|
||||||
|
let &t_8f = "\<Esc>[38;2;%lu;%lu;%lum"
|
||||||
|
let &t_8b = "\<Esc>[48;2;%lu;%lu;%lum"
|
||||||
|
set termguicolors
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Search and UI
|
||||||
|
set hlsearch
|
||||||
|
set incsearch
|
||||||
|
set ignorecase
|
||||||
|
set smartcase
|
||||||
|
set wildmenu
|
||||||
|
|
||||||
|
" Tab Settings (Standardized for the Lab)
|
||||||
|
set tabstop=4
|
||||||
|
set shiftwidth=4
|
||||||
|
set expandtab
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
- name: Install Vim
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: vim
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Configure Vim for root
|
||||||
|
include_tasks: setup_user.yml
|
||||||
|
vars:
|
||||||
|
v_user: root
|
||||||
|
|
||||||
|
- name: Configure Vim for volker
|
||||||
|
include_tasks: setup_user.yml
|
||||||
|
vars:
|
||||||
|
v_user: volker
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
- name: Define home path
|
||||||
|
set_fact:
|
||||||
|
v_home: "{{ '/root' if v_user == 'root' else '/home/' + v_user }}"
|
||||||
|
|
||||||
|
- name: Create .vim directories
|
||||||
|
file:
|
||||||
|
path: "{{ v_home }}/.vim/autoload"
|
||||||
|
state: directory
|
||||||
|
owner: "{{ v_user }}"
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Install vim-plug
|
||||||
|
get_url:
|
||||||
|
url: https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
|
||||||
|
dest: "{{ v_home }}/.vim/autoload/plug.vim"
|
||||||
|
owner: "{{ v_user }}"
|
||||||
|
|
||||||
|
- name: Deploy .vimrc from template
|
||||||
|
template:
|
||||||
|
src: vimrc.j2
|
||||||
|
dest: "{{ v_home }}/.vimrc"
|
||||||
|
owner: "{{ v_user }}"
|
||||||
|
|
||||||
|
- name: Run PlugInstall
|
||||||
|
become_user: "{{ v_user }}"
|
||||||
|
command: vim +PlugInstall +qall
|
||||||
|
changed_when: false
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
" --- Basic Quality of Life ---
|
||||||
|
set nocompatible
|
||||||
|
filetype plugin indent on
|
||||||
|
syntax on
|
||||||
|
set number
|
||||||
|
set relativenumber
|
||||||
|
set mouse=r
|
||||||
|
set clipboard=unnamedplus
|
||||||
|
|
||||||
|
" --- Plugin Management (vim-plug) ---
|
||||||
|
call plug#begin('~/.vim/plugged')
|
||||||
|
Plug 'ojroques/vim-oscyank'
|
||||||
|
call plug#end()
|
||||||
|
|
||||||
|
" --- Ghostty / Modern Terminal Compatibility ---
|
||||||
|
if (has("termguicolors"))
|
||||||
|
" Fix for some older vim versions in modern terms
|
||||||
|
let &t_8f = "\<Esc>[38;2;%lu;%lu;%lum"
|
||||||
|
let &t_8b = "\<Esc>[48;2;%lu;%lu;%lum"
|
||||||
|
set termguicolors
|
||||||
|
endif
|
||||||
|
|
||||||
|
" --- Smart OSC52 Yanking (Works with Ghostty) ---
|
||||||
|
" This allows copying to your Mac clipboard over SSH
|
||||||
|
if has('autocmd')
|
||||||
|
autocmd TextYankPost * if v:event.operator is 'y' && v:event.regname is '' | execute 'OSCYankReg "' | endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
" --- UI and Search ---
|
||||||
|
set hlsearch
|
||||||
|
set incsearch
|
||||||
|
set ignorecase
|
||||||
|
set smartcase
|
||||||
|
set wildmenu
|
||||||
|
|
||||||
|
" --- Tab Settings (Standardized for the Lab) ---
|
||||||
|
set tabstop=4
|
||||||
|
set shiftwidth=4
|
||||||
|
set expandtab
|
||||||
|
|
||||||
|
" --- User Specific Logic ---
|
||||||
|
{% if v_user == 'root' %}
|
||||||
|
" Visual warning that you are editing as ROOT
|
||||||
|
hi StatusLine ctermbg=red ctermfg=white
|
||||||
|
hi StatusLineNC ctermbg=red ctermfg=gray
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
" Add user identity to status line
|
||||||
|
set statusline=%f\ %h%m%r%=USER:\ {{ v_user }}\ %p%%
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
#- name: Provision All Nodes
|
||||||
|
# hosts: all_nodes
|
||||||
|
# become: yes
|
||||||
|
# roles:
|
||||||
|
# - role: common # Identity, mDNS, Base packages
|
||||||
|
# - role: security # SSH Keys
|
||||||
|
# - role: vim # The multi-user Ghostty setup
|
||||||
|
|
||||||
|
|
||||||
|
# TIER 1: All nodes get the exporter so they can be "seen"
|
||||||
|
- name: Provision All Nodes
|
||||||
|
hosts: all_nodes
|
||||||
|
become: true
|
||||||
|
roles:
|
||||||
|
- common # This should install prometheus-node-exporter
|
||||||
|
- security
|
||||||
|
- vim
|
||||||
|
- monitoring
|
||||||
|
## TIER 2: ONLY the monitor node gets the heavy stack
|
||||||
|
#- name: Setup Monitoring Central
|
||||||
|
# hosts: monitor
|
||||||
|
# become: true
|
||||||
|
# roles:
|
||||||
|
# - monitoring # This installs Grafana, InfluxDB, and the Prometheus Server
|
||||||
|
|
||||||
|
|
||||||
|
# Setup the Fileserver (The part we just built)
|
||||||
|
- name: Setup File Storage
|
||||||
|
hosts: smb_servers # Use a group name here
|
||||||
|
tags: fileserver
|
||||||
|
roles:
|
||||||
|
- fileserver
|
||||||
|
|
||||||
|
- name: Setup Pi Backup Storage
|
||||||
|
hosts: goldeneye # <--- Only runs on your Pi
|
||||||
|
roles:
|
||||||
|
- backup_server
|
||||||
|
|
||||||
|
- name: Provision Reverse Proxy Server
|
||||||
|
hosts: reverse_proxies
|
||||||
|
roles:
|
||||||
|
- reverse_proxy
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
- name: Check if reboot is required
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: /var/run/reboot-required
|
||||||
|
register: reboot_required_file
|
||||||
|
|
||||||
|
- name: Perform Reboot Block
|
||||||
|
when: reboot_required_file.stat.exists
|
||||||
|
block:
|
||||||
|
- name: Handle Proxmox Guests (Endor only)
|
||||||
|
when: inventory_hostname == 'endor'
|
||||||
|
ansible.builtin.shell: "pvesh create /nodes/localhost/stopall"
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Reboot the machine
|
||||||
|
ansible.builtin.reboot:
|
||||||
|
msg: "Reboot initiated by Ansible for updates"
|
||||||
|
reboot_timeout: 600
|
||||||
|
post_reboot_delay: 30
|
||||||
|
|
||||||
|
- name: Wait for Node Exporter to respond
|
||||||
|
ansible.builtin.wait_for:
|
||||||
|
port: 9100
|
||||||
|
host: "{{ ansible_host }}"
|
||||||
|
delay: 10
|
||||||
|
timeout: 300
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
[agent]
|
||||||
|
interval = "10s"
|
||||||
|
round_interval = true
|
||||||
|
metric_batch_size = 1000
|
||||||
|
metric_buffer_limit = 10000
|
||||||
|
collection_jitter = "0s"
|
||||||
|
flush_interval = "10s"
|
||||||
|
hostname = "{{ inventory_hostname }}"
|
||||||
|
|
||||||
|
[[outputs.influxdb]]
|
||||||
|
urls = ["http://192.168.123.101:8086"] # Your InfluxDB IP
|
||||||
|
database = "proxmox"
|
||||||
|
|
||||||
|
[[inputs.cpu]]
|
||||||
|
percpu = true
|
||||||
|
totalcpu = true
|
||||||
|
collect_cpu_time = false
|
||||||
|
report_active = false
|
||||||
|
[[inputs.mem]]
|
||||||
|
[[inputs.disk]]
|
||||||
|
ignore_fs = ["tmpfs", "devtmpfs", "devfs", "iso9660", "overlay", "aufs", "squashfs"]
|
||||||
|
[[inputs.system]]
|
||||||
|
[[inputs.temp]] # This is the magic for the Raspberry Pi temperature
|
||||||
|
|
||||||
|
[[inputs.zfs]]
|
||||||
|
## ZFS pool metrics (This is what we need for the bar)
|
||||||
|
poolMetrics = true
|
||||||
|
## Dataset metrics (Optional: for individual LXC/VM disks)
|
||||||
|
datasetMetrics = true
|
||||||
|
|
||||||
|
# Keep your other inputs too
|
||||||
|
[[inputs.cpu]]
|
||||||
|
[[inputs.mem]]
|
||||||
|
[[inputs.disk]]
|
||||||
|
[[inputs.system]]
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
$ANSIBLE_VAULT;1.1;AES256
|
||||||
|
64336435353835363662616666663737643962323663353663313265656231366466623739386265
|
||||||
|
3132633630373533316139316163363966333564653639640a303163353039666231336434373366
|
||||||
|
37623438363065633539353964613264653635613365343438326435303934393866336639373932
|
||||||
|
3336663165663338620a383536363061636230313136396364626164623431303837366462346334
|
||||||
|
66376266306336383666313966353930326261623361393639343033346262326336623662386662
|
||||||
|
61353063366531333765626438636133613635613361386665373438303931616131353561626436
|
||||||
|
35343334626462653430643662306537393333646233623632343934303366636635343166663665
|
||||||
|
64663436333666333734
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
- name: Update and Upgrade All Nodes
|
||||||
|
hosts: all_nodes
|
||||||
|
gather_facts: yes
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Run apt update and apt upgrade
|
||||||
|
ansible.builtin.apt:
|
||||||
|
upgrade: dist
|
||||||
|
update_cache: yes
|
||||||
|
autoremove: yes
|
||||||
|
autoclean: yes
|
||||||
|
when: ansible_os_family == "Debian"
|
||||||
|
|
||||||
|
- name: Check if a reboot is required
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: /var/run/reboot-required
|
||||||
|
register: reboot_required_file
|
||||||
|
|
||||||
|
- name: Reboot the server if required (VMs only)
|
||||||
|
ansible.builtin.reboot:
|
||||||
|
msg: "Reboot initiated by Ansible due to kernel updates"
|
||||||
|
connect_timeout: 5
|
||||||
|
reboot_timeout: 300
|
||||||
|
pre_reboot_delay: 0
|
||||||
|
post_reboot_delay: 30
|
||||||
|
test_command: whoami
|
||||||
|
when:
|
||||||
|
- reboot_required_file.stat.exists
|
||||||
|
- "'physical_iron' not in group_names" # Verhindert, dass Proxmox-Nodes ungeplant neustarten
|
||||||
Reference in New Issue
Block a user