Sanitized mirror from private repository - 2026-04-20 01:32:01 UTC
This commit is contained in:
206
ansible/homelab/README.md
Normal file
206
ansible/homelab/README.md
Normal file
@@ -0,0 +1,206 @@
|
||||
# Homelab Ansible Playbooks
|
||||
|
||||
Automated deployment and management of all homelab services across all hosts.
|
||||
|
||||
## 📁 Directory Structure
|
||||
|
||||
```
|
||||
ansible/homelab/
|
||||
├── ansible.cfg # Ansible configuration
|
||||
├── inventory.yml # All hosts inventory
|
||||
├── site.yml # Master playbook
|
||||
├── generate_playbooks.py # Script to regenerate playbooks from compose files
|
||||
├── group_vars/ # Variables by group
|
||||
│ ├── all.yml # Global variables
|
||||
│ ├── synology.yml # Synology NAS specific
|
||||
│ └── vms.yml # Virtual machines specific
|
||||
├── host_vars/ # Variables per host (auto-generated)
|
||||
│ ├── atlantis.yml # 53 services
|
||||
│ ├── calypso.yml # 24 services
|
||||
│ ├── homelab_vm.yml # 33 services
|
||||
│ └── ...
|
||||
├── playbooks/ # Individual playbooks
|
||||
│ ├── common/ # Shared playbooks
|
||||
│ │ ├── install_docker.yml
|
||||
│ │ └── setup_directories.yml
|
||||
│ ├── deploy_atlantis.yml
|
||||
│ ├── deploy_calypso.yml
|
||||
│ └── ...
|
||||
└── roles/ # Reusable roles
|
||||
├── docker_stack/ # Deploy docker-compose stacks
|
||||
└── directory_setup/ # Create directory structures
|
||||
```
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### Prerequisites
|
||||
- Ansible 2.12+
|
||||
- SSH access to all hosts (via Tailscale)
|
||||
- Python 3.8+
|
||||
|
||||
### Installation
|
||||
```bash
|
||||
pip install ansible
|
||||
```
|
||||
|
||||
### Deploy Everything
|
||||
```bash
|
||||
cd ansible/homelab
|
||||
ansible-playbook site.yml
|
||||
```
|
||||
|
||||
### Deploy to Specific Host
|
||||
```bash
|
||||
ansible-playbook site.yml --limit atlantis
|
||||
```
|
||||
|
||||
### Deploy by Category
|
||||
```bash
|
||||
# Deploy all Synology hosts
|
||||
ansible-playbook site.yml --tags synology
|
||||
|
||||
# Deploy all VMs
|
||||
ansible-playbook site.yml --tags vms
|
||||
```
|
||||
|
||||
### Check Mode (Dry Run)
|
||||
```bash
|
||||
ansible-playbook site.yml --check --diff
|
||||
```
|
||||
|
||||
## 📋 Host Inventory
|
||||
|
||||
| Host | Category | Services | Description |
|
||||
|------|----------|----------|-------------|
|
||||
| atlantis | synology | 53 | Primary NAS (DS1823xs+) |
|
||||
| calypso | synology | 24 | Secondary NAS (DS920+) |
|
||||
| setillo | synology | 2 | Remote NAS |
|
||||
| guava | physical | 8 | TrueNAS Scale |
|
||||
| concord_nuc | physical | 11 | Intel NUC |
|
||||
| homelab_vm | vms | 33 | Primary VM |
|
||||
| rpi5_vish | edge | 3 | Raspberry Pi 5 |
|
||||
|
||||
## 🔧 Configuration
|
||||
|
||||
### Vault Secrets
|
||||
Sensitive data should be stored in Ansible Vault:
|
||||
|
||||
```bash
|
||||
# Create vault password file (DO NOT commit this)
|
||||
echo "your-vault-password" > .vault_pass
|
||||
|
||||
# Encrypt a variable
|
||||
ansible-vault encrypt_string 'my-secret' --name 'api_key'
|
||||
|
||||
# Run playbook with vault
|
||||
ansible-playbook site.yml --vault-password-file .vault_pass
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
Create a `.env` file for each service or use host_vars:
|
||||
|
||||
```yaml
|
||||
# host_vars/atlantis.yml
|
||||
vault_plex_claim_token: !vault |
|
||||
$ANSIBLE_VAULT;1.1;AES256
|
||||
...
|
||||
```
|
||||
|
||||
## 📝 Adding New Services
|
||||
|
||||
### Method 1: Add docker-compose file
|
||||
1. Add your `docker-compose.yml` to `hosts/<category>/<host>/<service>/`
|
||||
2. Run the generator:
|
||||
```bash
|
||||
python3 generate_playbooks.py
|
||||
```
|
||||
|
||||
### Method 2: Manual addition
|
||||
1. Add service to `host_vars/<host>.yml`:
|
||||
```yaml
|
||||
host_services:
|
||||
- name: my_service
|
||||
stack_dir: my_service
|
||||
compose_file: hosts/synology/atlantis/my_service.yaml
|
||||
enabled: true
|
||||
```
|
||||
|
||||
## 🏷️ Tags
|
||||
|
||||
| Tag | Description |
|
||||
|-----|-------------|
|
||||
| `synology` | All Synology NAS hosts |
|
||||
| `vms` | All virtual machines |
|
||||
| `physical` | Physical servers |
|
||||
| `edge` | Edge devices (RPi, etc.) |
|
||||
| `arr-suite` | Media management (Sonarr, Radarr, etc.) |
|
||||
| `monitoring` | Prometheus, Grafana, etc. |
|
||||
|
||||
## 📊 Service Categories
|
||||
|
||||
### Media & Entertainment
|
||||
- Plex, Jellyfin, Tautulli
|
||||
- Sonarr, Radarr, Lidarr, Prowlarr
|
||||
- Jellyseerr, Overseerr
|
||||
|
||||
### Productivity
|
||||
- Paperless-ngx, Stirling PDF
|
||||
- Joplin, Dokuwiki
|
||||
- Syncthing
|
||||
|
||||
### Infrastructure
|
||||
- Nginx Proxy Manager
|
||||
- Traefik, Cloudflare Tunnel
|
||||
- AdGuard Home, Pi-hole
|
||||
|
||||
### Monitoring
|
||||
- Prometheus, Grafana
|
||||
- Uptime Kuma, Dozzle
|
||||
- Node Exporter
|
||||
|
||||
### Security
|
||||
- Vaultwarden
|
||||
- Authentik
|
||||
- Headscale
|
||||
|
||||
## 🔄 Regenerating Playbooks
|
||||
|
||||
If you modify docker-compose files directly:
|
||||
|
||||
```bash
|
||||
python3 generate_playbooks.py
|
||||
```
|
||||
|
||||
This will:
|
||||
1. Scan all `hosts/` directories for compose files
|
||||
2. Update `host_vars/` with service lists
|
||||
3. Regenerate individual host playbooks
|
||||
4. Update the master `site.yml`
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Test connectivity
|
||||
```bash
|
||||
ansible all -m ping
|
||||
```
|
||||
|
||||
### Test specific host
|
||||
```bash
|
||||
ansible atlantis -m ping
|
||||
```
|
||||
|
||||
### Verbose output
|
||||
```bash
|
||||
ansible-playbook site.yml -vvv
|
||||
```
|
||||
|
||||
### List tasks without running
|
||||
```bash
|
||||
ansible-playbook site.yml --list-tasks
|
||||
```
|
||||
|
||||
## 📚 Resources
|
||||
|
||||
- [Ansible Documentation](https://docs.ansible.com/)
|
||||
- [Docker Compose Reference](https://docs.docker.com/compose/compose-file/)
|
||||
- [Tailscale Documentation](https://tailscale.com/kb/)
|
||||
18
ansible/homelab/ansible.cfg
Normal file
18
ansible/homelab/ansible.cfg
Normal file
@@ -0,0 +1,18 @@
|
||||
[defaults]
|
||||
inventory = inventory.yml
|
||||
roles_path = roles
|
||||
host_key_checking = False
|
||||
retry_files_enabled = False
|
||||
gathering = smart
|
||||
fact_caching = jsonfile
|
||||
fact_caching_connection = /tmp/ansible_facts_cache
|
||||
fact_caching_timeout = 86400
|
||||
stdout_callback = yaml
|
||||
interpreter_python = auto_silent
|
||||
|
||||
[privilege_escalation]
|
||||
become = False
|
||||
|
||||
[ssh_connection]
|
||||
pipelining = True
|
||||
ssh_args = -o ControlMaster=auto -o ControlPersist=60s
|
||||
296
ansible/homelab/generate_playbooks.py
Normal file
296
ansible/homelab/generate_playbooks.py
Normal file
@@ -0,0 +1,296 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Generate Ansible playbooks from existing docker-compose files in the homelab repo.
|
||||
This script scans the hosts/ directory and creates deployment playbooks.
|
||||
"""
|
||||
|
||||
import os
|
||||
import yaml
|
||||
from pathlib import Path
|
||||
from collections import defaultdict
|
||||
|
||||
REPO_ROOT = Path(__file__).parent.parent.parent
|
||||
HOSTS_DIR = REPO_ROOT / "hosts"
|
||||
ANSIBLE_DIR = Path(__file__).parent
|
||||
PLAYBOOKS_DIR = ANSIBLE_DIR / "playbooks"
|
||||
HOST_VARS_DIR = ANSIBLE_DIR / "host_vars"
|
||||
|
||||
# Mapping of directory names to ansible host names
|
||||
HOST_MAPPING = {
|
||||
"atlantis": "atlantis",
|
||||
"calypso": "calypso",
|
||||
"setillo": "setillo",
|
||||
"guava": "guava",
|
||||
"concord-nuc": "concord_nuc",
|
||||
"anubis": "anubis",
|
||||
"homelab-vm": "homelab_vm",
|
||||
"chicago-vm": "chicago_vm",
|
||||
"bulgaria-vm": "bulgaria_vm",
|
||||
"contabo-vm": "contabo_vm",
|
||||
"rpi5-vish": "rpi5_vish",
|
||||
"tdarr-node": "tdarr_node",
|
||||
}
|
||||
|
||||
# Host categories for grouping
|
||||
HOST_CATEGORIES = {
|
||||
"synology": ["atlantis", "calypso", "setillo"],
|
||||
"physical": ["guava", "concord-nuc", "anubis"],
|
||||
"vms": ["homelab-vm", "chicago-vm", "bulgaria-vm", "contabo-vm", "matrix-ubuntu-vm"],
|
||||
"edge": ["rpi5-vish", "nvidia_shield"],
|
||||
"proxmox": ["tdarr-node"],
|
||||
}
|
||||
|
||||
|
||||
def find_compose_files():
|
||||
"""Find all docker-compose files in the hosts directory."""
|
||||
compose_files = defaultdict(list)
|
||||
|
||||
for yaml_file in HOSTS_DIR.rglob("*.yaml"):
|
||||
if ".git" in str(yaml_file):
|
||||
continue
|
||||
compose_files[yaml_file.parent].append(yaml_file)
|
||||
|
||||
for yml_file in HOSTS_DIR.rglob("*.yml"):
|
||||
if ".git" in str(yml_file):
|
||||
continue
|
||||
compose_files[yml_file.parent].append(yml_file)
|
||||
|
||||
return compose_files
|
||||
|
||||
|
||||
def get_host_from_path(file_path):
|
||||
"""Extract REDACTED_APP_PASSWORD path."""
|
||||
parts = file_path.relative_to(HOSTS_DIR).parts
|
||||
|
||||
# Structure: hosts/<category>/<host>/...
|
||||
if len(parts) >= 2:
|
||||
category = parts[0]
|
||||
host = parts[1]
|
||||
return category, host
|
||||
return None, None
|
||||
|
||||
|
||||
def extract_service_name(file_path):
|
||||
"""Extract service name from file path."""
|
||||
# Get the service name from parent directory or filename
|
||||
if file_path.name in ["docker-compose.yml", "docker-compose.yaml"]:
|
||||
return file_path.parent.name
|
||||
else:
|
||||
return file_path.stem.replace("-", "_").replace(".", "_")
|
||||
|
||||
|
||||
def is_compose_file(file_path):
|
||||
"""Check if file looks like a docker-compose file."""
|
||||
try:
|
||||
with open(file_path, 'r') as f:
|
||||
content = yaml.safe_load(f)
|
||||
if content and isinstance(content, dict):
|
||||
return 'services' in content or 'version' in content
|
||||
except:
|
||||
pass
|
||||
return False
|
||||
|
||||
|
||||
def generate_service_vars(host, services):
|
||||
"""Generate host_vars with service definitions."""
|
||||
service_list = []
|
||||
|
||||
for service_path, service_name in services:
|
||||
rel_path = service_path.relative_to(REPO_ROOT)
|
||||
|
||||
# Determine the stack directory name
|
||||
if service_path.name in ["docker-compose.yml", "docker-compose.yaml"]:
|
||||
stack_dir = service_path.parent.name
|
||||
else:
|
||||
stack_dir = service_name
|
||||
|
||||
service_entry = {
|
||||
"name": service_name,
|
||||
"stack_dir": stack_dir,
|
||||
"compose_file": str(rel_path),
|
||||
"enabled": True,
|
||||
}
|
||||
|
||||
# Check for .env file
|
||||
env_file = service_path.parent / ".env"
|
||||
stack_env = service_path.parent / "stack.env"
|
||||
if env_file.exists():
|
||||
service_entry["env_file"] = str(env_file.relative_to(REPO_ROOT))
|
||||
elif stack_env.exists():
|
||||
service_entry["env_file"] = str(stack_env.relative_to(REPO_ROOT))
|
||||
|
||||
service_list.append(service_entry)
|
||||
|
||||
return service_list
|
||||
|
||||
|
||||
def generate_host_playbook(host_name, ansible_host, services, category):
|
||||
"""Generate a playbook for a specific host."""
|
||||
|
||||
# Create header comment
|
||||
header = f"""---
|
||||
# Deployment playbook for {host_name}
|
||||
# Category: {category}
|
||||
# Services: {len(services)}
|
||||
#
|
||||
# Usage:
|
||||
# ansible-playbook playbooks/deploy_{ansible_host}.yml
|
||||
# ansible-playbook playbooks/deploy_{ansible_host}.yml -e "stack_deploy=false"
|
||||
# ansible-playbook playbooks/deploy_{ansible_host}.yml --check
|
||||
|
||||
"""
|
||||
|
||||
playbook = [
|
||||
{
|
||||
"name": f"Deploy services to {host_name}",
|
||||
"hosts": ansible_host,
|
||||
"gather_facts": True,
|
||||
"vars": {
|
||||
"services": "{{ host_services | default([]) }}"
|
||||
},
|
||||
"tasks": [
|
||||
{
|
||||
"name": "Display deployment info",
|
||||
"ansible.builtin.debug": {
|
||||
"msg": "Deploying {{ services | length }} services to {{ inventory_hostname }}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Ensure docker data directory exists",
|
||||
"ansible.builtin.file": {
|
||||
"path": "{{ docker_data_path }}",
|
||||
"state": "directory",
|
||||
"mode": "0755"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Deploy each enabled service",
|
||||
"ansible.builtin.include_role": {
|
||||
"name": "docker_stack"
|
||||
},
|
||||
"vars": {
|
||||
"stack_name": "{{ item.stack_dir }}",
|
||||
"stack_compose_file": "{{ item.compose_file }}",
|
||||
"stack_env_file": "{{ item.env_file | default(omit) }}"
|
||||
},
|
||||
"loop": "{{ services }}",
|
||||
"loop_control": {
|
||||
"label": "{{ item.name }}"
|
||||
},
|
||||
"when": "item.enabled | default(true)"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
return header, playbook
|
||||
|
||||
|
||||
def main():
|
||||
"""Main function to generate all playbooks."""
|
||||
print("=" * 60)
|
||||
print("Generating Ansible Playbooks from Homelab Repository")
|
||||
print("=" * 60)
|
||||
|
||||
# Ensure directories exist
|
||||
PLAYBOOKS_DIR.mkdir(parents=True, exist_ok=True)
|
||||
HOST_VARS_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Find all compose files
|
||||
compose_files = find_compose_files()
|
||||
|
||||
# Organize by host
|
||||
hosts_services = defaultdict(list)
|
||||
|
||||
for directory, files in compose_files.items():
|
||||
category, host = get_host_from_path(directory)
|
||||
if not host:
|
||||
continue
|
||||
|
||||
for f in files:
|
||||
if is_compose_file(f):
|
||||
service_name = extract_service_name(f)
|
||||
hosts_services[(category, host)].append((f, service_name))
|
||||
|
||||
# Generate playbooks and host_vars
|
||||
all_hosts = {}
|
||||
|
||||
for (category, host), services in sorted(hosts_services.items()):
|
||||
ansible_host = HOST_MAPPING.get(host, host.replace("-", "_"))
|
||||
|
||||
print(f"\n[{category}/{host}] Found {len(services)} services:")
|
||||
for service_path, service_name in services:
|
||||
print(f" - {service_name}")
|
||||
|
||||
# Generate host_vars
|
||||
service_vars = generate_service_vars(host, services)
|
||||
host_vars = {
|
||||
"host_services": service_vars
|
||||
}
|
||||
|
||||
host_vars_file = HOST_VARS_DIR / f"{ansible_host}.yml"
|
||||
with open(host_vars_file, 'w') as f:
|
||||
f.write("---\n")
|
||||
f.write(f"# Auto-generated host variables for {host}\n")
|
||||
f.write(f"# Services deployed to this host\n\n")
|
||||
yaml.dump(host_vars, f, default_flow_style=False, sort_keys=False)
|
||||
|
||||
# Generate individual host playbook
|
||||
header, playbook = generate_host_playbook(host, ansible_host, services, category)
|
||||
playbook_file = PLAYBOOKS_DIR / f"deploy_{ansible_host}.yml"
|
||||
with open(playbook_file, 'w') as f:
|
||||
f.write(header)
|
||||
yaml.dump(playbook, f, default_flow_style=False, sort_keys=False)
|
||||
|
||||
all_hosts[ansible_host] = {
|
||||
"category": category,
|
||||
"host": host,
|
||||
"services": len(services)
|
||||
}
|
||||
|
||||
# Generate master playbook
|
||||
master_playbook = [
|
||||
{
|
||||
"name": "Deploy all homelab services",
|
||||
"hosts": "localhost",
|
||||
"gather_facts": False,
|
||||
"tasks": [
|
||||
{
|
||||
"name": "Display deployment plan",
|
||||
"ansible.builtin.debug": {
|
||||
"msg": "Deploying services to all hosts. Use --limit to target specific hosts."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
# Add imports for each host
|
||||
for ansible_host, info in sorted(all_hosts.items()):
|
||||
master_playbook.append({
|
||||
"name": f"Deploy to {info['host']} ({info['services']} services)",
|
||||
"ansible.builtin.import_playbook": f"playbooks/deploy_{ansible_host}.yml",
|
||||
"tags": [info['category'], ansible_host]
|
||||
})
|
||||
|
||||
master_file = ANSIBLE_DIR / "site.yml"
|
||||
with open(master_file, 'w') as f:
|
||||
f.write("---\n")
|
||||
f.write("# Master Homelab Deployment Playbook\n")
|
||||
f.write("# Auto-generated from docker-compose files\n")
|
||||
f.write("#\n")
|
||||
f.write("# Usage:\n")
|
||||
f.write("# Deploy everything: ansible-playbook site.yml\n")
|
||||
f.write("# Deploy specific host: ansible-playbook site.yml --limit atlantis\n")
|
||||
f.write("# Deploy by category: ansible-playbook site.yml --tags synology\n")
|
||||
f.write("#\n\n")
|
||||
yaml.dump(master_playbook, f, default_flow_style=False, sort_keys=False)
|
||||
|
||||
print(f"\n{'=' * 60}")
|
||||
print(f"Generated playbooks for {len(all_hosts)} hosts")
|
||||
print(f"Master playbook: {master_file}")
|
||||
print("=" * 60)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
205
ansible/homelab/inventory.yml
Normal file
205
ansible/homelab/inventory.yml
Normal file
@@ -0,0 +1,205 @@
|
||||
---
|
||||
# Homelab Ansible Inventory
|
||||
# All hosts accessible via Tailscale (tail.vish.gg)
|
||||
# Last reconciled: 2026-03-13
|
||||
#
|
||||
# This inventory is used by ansible/homelab/ deployment playbooks.
|
||||
# It is kept consistent with ansible/automation/hosts.ini.
|
||||
# hosts.ini is the canonical reference — update both when adding hosts.
|
||||
#
|
||||
# Host naming convention:
|
||||
# Matches automation/hosts.ini names where possible.
|
||||
# Underscores used where hyphens would break Ansible variable names.
|
||||
|
||||
all:
|
||||
vars:
|
||||
ansible_python_interpreter: /usr/bin/python3
|
||||
ansible_ssh_common_args: '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null'
|
||||
docker_compose_version: "2"
|
||||
|
||||
children:
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Synology NAS devices
|
||||
# ansible_become: false — Synology DSM does not use standard sudo
|
||||
# docker_data_path: /volume1/docker — DSM package manager path
|
||||
# -------------------------------------------------------------------------
|
||||
synology:
|
||||
vars:
|
||||
docker_data_path: /volume1/docker
|
||||
ansible_become: false
|
||||
docker_socket: /var/run/docker.sock
|
||||
docker_bin: sudo /var/packages/REDACTED_APP_PASSWORD/usr/bin/docker
|
||||
hosts:
|
||||
atlantis:
|
||||
ansible_host: 100.83.230.112
|
||||
ansible_user: vish
|
||||
ansible_port: 60000
|
||||
hostname: atlantis.vish.local
|
||||
description: "Primary NAS — Synology DS1823xs+"
|
||||
|
||||
calypso:
|
||||
ansible_host: 100.103.48.78
|
||||
ansible_user: Vish
|
||||
ansible_port: 62000
|
||||
hostname: calypso.vish.local
|
||||
description: "Secondary NAS — Synology DS920+"
|
||||
|
||||
setillo:
|
||||
ansible_host: 100.125.0.20
|
||||
ansible_user: vish
|
||||
ansible_port: 22
|
||||
hostname: setillo.vish.local
|
||||
description: "Remote NAS — Synology (Seattle offsite)"
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Raspberry Pi nodes
|
||||
# -------------------------------------------------------------------------
|
||||
rpi:
|
||||
vars:
|
||||
docker_data_path: /opt/docker
|
||||
ansible_become: true
|
||||
docker_bin: docker
|
||||
hosts:
|
||||
pi-5:
|
||||
ansible_host: 100.77.151.40
|
||||
ansible_user: vish
|
||||
hostname: pi-5.vish.local
|
||||
description: "Raspberry Pi 5 — uptime-kuma, monitoring"
|
||||
|
||||
pi-5-kevin:
|
||||
ansible_host: 100.123.246.75
|
||||
ansible_user: vish
|
||||
hostname: pi-5-kevin.vish.local
|
||||
description: "Raspberry Pi 5 (Kevin's)"
|
||||
# Note: frequently offline
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Hypervisors and infrastructure hosts
|
||||
# -------------------------------------------------------------------------
|
||||
hypervisors:
|
||||
vars:
|
||||
docker_data_path: /opt/docker
|
||||
ansible_become: true
|
||||
docker_bin: docker
|
||||
hosts:
|
||||
pve:
|
||||
ansible_host: 100.87.12.28
|
||||
ansible_user: root
|
||||
hostname: pve.vish.local
|
||||
description: "Proxmox VE hypervisor"
|
||||
# LXC 103: tdarr-node at 192.168.0.180 (LAN-only, no Tailscale)
|
||||
# LXC 104: headscale-test
|
||||
|
||||
truenas-scale:
|
||||
ansible_host: 100.75.252.64
|
||||
ansible_user: vish
|
||||
hostname: guava.vish.local
|
||||
description: "TrueNAS Scale — guava"
|
||||
docker_data_path: /mnt/pool/docker
|
||||
# WARNING: do NOT run apt update on TrueNAS — use web UI only
|
||||
|
||||
homeassistant:
|
||||
ansible_host: 100.112.186.90
|
||||
ansible_user: hassio
|
||||
hostname: homeassistant.vish.local
|
||||
description: "Home Assistant OS"
|
||||
# WARNING: exclude from apt updates — HA manages its own packages
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Remote and physical compute hosts
|
||||
# -------------------------------------------------------------------------
|
||||
remote:
|
||||
vars:
|
||||
docker_data_path: /opt/docker
|
||||
ansible_become: true
|
||||
docker_bin: docker
|
||||
hosts:
|
||||
vish-concord-nuc:
|
||||
ansible_host: 100.72.55.21
|
||||
ansible_user: vish
|
||||
hostname: concord-nuc.vish.local
|
||||
description: "Intel NUC — concord"
|
||||
|
||||
seattle:
|
||||
ansible_host: 100.82.197.124
|
||||
ansible_user: root
|
||||
hostname: seattle.vish.local
|
||||
description: "Seattle VPS (Contabo) — bookstack, surmai, pufferpanel"
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Local VMs on-site
|
||||
# -------------------------------------------------------------------------
|
||||
local_vms:
|
||||
vars:
|
||||
docker_data_path: /opt/docker
|
||||
ansible_become: true
|
||||
docker_bin: docker
|
||||
hosts:
|
||||
homelab:
|
||||
ansible_host: 100.67.40.126
|
||||
ansible_user: homelab
|
||||
hostname: homelab-vm.vish.local
|
||||
description: "Primary homelab VM — this machine"
|
||||
|
||||
matrix-ubuntu:
|
||||
ansible_host: 100.85.21.51
|
||||
ansible_user: test
|
||||
hostname: matrix-ubuntu.vish.local
|
||||
description: "Matrix/Mattermost Ubuntu VM"
|
||||
# LAN: 192.168.0.154
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Functional groups (mirrors automation/hosts.ini grouping)
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
# All reachable managed hosts — use this for most playbooks
|
||||
active:
|
||||
children:
|
||||
homelab_group:
|
||||
synology:
|
||||
rpi:
|
||||
hypervisors:
|
||||
remote:
|
||||
local_vms:
|
||||
|
||||
# Hosts using Calypso as APT proxy (apt-cacher-ng)
|
||||
debian_clients:
|
||||
hosts:
|
||||
homelab:
|
||||
pi-5:
|
||||
pi-5-kevin:
|
||||
vish-concord-nuc:
|
||||
pve:
|
||||
homeassistant:
|
||||
truenas-scale:
|
||||
|
||||
# Hosts running Portainer edge agents
|
||||
portainer_edge_agents:
|
||||
hosts:
|
||||
homelab:
|
||||
vish-concord-nuc:
|
||||
pi-5:
|
||||
calypso:
|
||||
|
||||
# Legacy compatibility group
|
||||
homelab_linux:
|
||||
children:
|
||||
homelab_group:
|
||||
synology:
|
||||
rpi:
|
||||
hypervisors:
|
||||
remote:
|
||||
|
||||
# Internal group to avoid name collision between host 'homelab' and group
|
||||
homelab_group:
|
||||
hosts:
|
||||
homelab:
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Offline / LAN-only hosts — not reachable via Tailscale
|
||||
# Documented here for reference, not targeted by playbooks
|
||||
# -------------------------------------------------------------------------
|
||||
# tdarr_node (LXC 103): 192.168.0.180 — access via: ssh pve "pct exec 103 -- <cmd>"
|
||||
# anubis: unknown IP — not in Tailscale
|
||||
# pi-5-kevin: 100.123.246.75 — frequently offline
|
||||
48
ansible/homelab/playbooks/common/backup_configs.yml
Normal file
48
ansible/homelab/playbooks/common/backup_configs.yml
Normal file
@@ -0,0 +1,48 @@
|
||||
---
|
||||
# Backup all docker-compose configs and data
|
||||
- name: Backup Docker configurations
|
||||
hosts: "{{ target_host | default('all') }}"
|
||||
gather_facts: true
|
||||
|
||||
vars:
|
||||
backup_dest: "{{ backup_path | default('/backup') }}"
|
||||
backup_timestamp: "{{ ansible_date_time.date }}_{{ ansible_date_time.hour }}{{ ansible_date_time.minute }}"
|
||||
|
||||
tasks:
|
||||
- name: Create backup directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ backup_dest }}/{{ inventory_hostname }}"
|
||||
state: directory
|
||||
mode: '0755'
|
||||
become: "{{ ansible_become | default(false) }}"
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Find all docker-compose files
|
||||
ansible.builtin.find:
|
||||
paths: "{{ docker_data_path }}"
|
||||
patterns: "docker-compose.yml,docker-compose.yaml,.env"
|
||||
recurse: true
|
||||
register: compose_files
|
||||
|
||||
- name: Archive docker configs
|
||||
ansible.builtin.archive:
|
||||
path: "{{ docker_data_path }}"
|
||||
dest: "/tmp/{{ inventory_hostname }}_configs_{{ backup_timestamp }}.tar.gz"
|
||||
format: gz
|
||||
exclude_path:
|
||||
- "*/data/*"
|
||||
- "*/logs/*"
|
||||
- "*/cache/*"
|
||||
become: "{{ ansible_become | default(false) }}"
|
||||
|
||||
- name: Fetch backup to control node
|
||||
ansible.builtin.fetch:
|
||||
src: "/tmp/{{ inventory_hostname }}_configs_{{ backup_timestamp }}.tar.gz"
|
||||
dest: "{{ backup_dest }}/{{ inventory_hostname }}/"
|
||||
flat: true
|
||||
|
||||
- name: Clean up remote archive
|
||||
ansible.builtin.file:
|
||||
path: "/tmp/{{ inventory_hostname }}_configs_{{ backup_timestamp }}.tar.gz"
|
||||
state: absent
|
||||
become: "{{ ansible_become | default(false) }}"
|
||||
55
ansible/homelab/playbooks/common/install_docker.yml
Normal file
55
ansible/homelab/playbooks/common/install_docker.yml
Normal file
@@ -0,0 +1,55 @@
|
||||
---
|
||||
# Install Docker on a host (for non-Synology systems)
|
||||
- name: Install Docker
|
||||
hosts: "{{ target_host | default('all:!synology') }}"
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
tasks:
|
||||
- name: Install prerequisites
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- apt-transport-https
|
||||
- ca-certificates
|
||||
- curl
|
||||
- gnupg
|
||||
- lsb-release
|
||||
- python3-pip
|
||||
state: present
|
||||
update_cache: true
|
||||
when: ansible_os_family == "Debian"
|
||||
|
||||
- name: Add Docker GPG key
|
||||
ansible.builtin.apt_key:
|
||||
url: https://download.docker.com/linux/{{ ansible_distribution | lower }}/gpg
|
||||
state: present
|
||||
when: ansible_os_family == "Debian"
|
||||
|
||||
- name: Add Docker repository
|
||||
ansible.builtin.apt_repository:
|
||||
repo: "deb https://download.docker.com/linux/{{ ansible_distribution | lower }} {{ ansible_distribution_release }} stable"
|
||||
state: present
|
||||
when: ansible_os_family == "Debian"
|
||||
|
||||
- name: Install Docker
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- docker-ce
|
||||
- docker-ce-cli
|
||||
- containerd.io
|
||||
- docker-compose-plugin
|
||||
state: present
|
||||
update_cache: true
|
||||
when: ansible_os_family == "Debian"
|
||||
|
||||
- name: Ensure Docker service is running
|
||||
ansible.builtin.service:
|
||||
name: docker
|
||||
state: started
|
||||
enabled: true
|
||||
|
||||
- name: Add user to docker group
|
||||
ansible.builtin.user:
|
||||
name: "{{ ansible_user }}"
|
||||
groups: docker
|
||||
append: true
|
||||
27
ansible/homelab/playbooks/common/logs.yml
Normal file
27
ansible/homelab/playbooks/common/logs.yml
Normal file
@@ -0,0 +1,27 @@
|
||||
---
|
||||
# View logs for a specific service
|
||||
# Usage: ansible-playbook playbooks/common/logs.yml -e "service_name=plex" -e "target_host=atlantis"
|
||||
- name: View service logs
|
||||
hosts: "{{ target_host }}"
|
||||
gather_facts: false
|
||||
|
||||
vars:
|
||||
log_lines: 100
|
||||
follow_logs: false
|
||||
|
||||
tasks:
|
||||
- name: Validate service_name is provided
|
||||
ansible.builtin.fail:
|
||||
msg: "service_name variable is required. Use -e 'service_name=<name>'"
|
||||
when: service_name is not defined
|
||||
|
||||
- name: Get service logs
|
||||
ansible.builtin.command:
|
||||
cmd: "docker compose logs --tail={{ log_lines }} {{ '--follow' if follow_logs else '' }}"
|
||||
chdir: "{{ docker_data_path }}/{{ service_name }}"
|
||||
register: logs_result
|
||||
become: "{{ ansible_become | default(false) }}"
|
||||
|
||||
- name: Display logs
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ logs_result.stdout }}"
|
||||
23
ansible/homelab/playbooks/common/restart_service.yml
Normal file
23
ansible/homelab/playbooks/common/restart_service.yml
Normal file
@@ -0,0 +1,23 @@
|
||||
---
|
||||
# Restart a specific service
|
||||
# Usage: ansible-playbook playbooks/common/restart_service.yml -e "service_name=plex" -e "target_host=atlantis"
|
||||
- name: Restart Docker service
|
||||
hosts: "{{ target_host }}"
|
||||
gather_facts: false
|
||||
|
||||
tasks:
|
||||
- name: Validate service_name is provided
|
||||
ansible.builtin.fail:
|
||||
msg: "service_name variable is required. Use -e 'service_name=<name>'"
|
||||
when: service_name is not defined
|
||||
|
||||
- name: Restart service
|
||||
ansible.builtin.command:
|
||||
cmd: docker compose restart
|
||||
chdir: "{{ docker_data_path }}/{{ service_name }}"
|
||||
register: restart_result
|
||||
become: "{{ ansible_become | default(false) }}"
|
||||
|
||||
- name: Display result
|
||||
ansible.builtin.debug:
|
||||
msg: "Service {{ service_name }} restarted on {{ inventory_hostname }}"
|
||||
34
ansible/homelab/playbooks/common/setup_directories.yml
Normal file
34
ansible/homelab/playbooks/common/setup_directories.yml
Normal file
@@ -0,0 +1,34 @@
|
||||
---
|
||||
# Setup base directories for Docker services
|
||||
- name: Setup Docker directories
|
||||
hosts: "{{ target_host | default('all') }}"
|
||||
gather_facts: true
|
||||
|
||||
tasks:
|
||||
- name: Create base docker directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ docker_data_path }}"
|
||||
state: directory
|
||||
mode: '0755'
|
||||
become: "{{ ansible_become | default(false) }}"
|
||||
|
||||
- name: Create common directories
|
||||
ansible.builtin.file:
|
||||
path: "{{ docker_data_path }}/{{ item }}"
|
||||
state: directory
|
||||
mode: '0755'
|
||||
loop:
|
||||
- configs
|
||||
- data
|
||||
- logs
|
||||
- backups
|
||||
become: "{{ ansible_become | default(false) }}"
|
||||
|
||||
- name: Create service directories from host_services
|
||||
ansible.builtin.file:
|
||||
path: "{{ docker_data_path }}/{{ item.stack_dir }}"
|
||||
state: directory
|
||||
mode: '0755'
|
||||
loop: "{{ host_services | default([]) }}"
|
||||
when: host_services is defined
|
||||
become: "{{ ansible_become | default(false) }}"
|
||||
49
ansible/homelab/playbooks/common/status.yml
Normal file
49
ansible/homelab/playbooks/common/status.yml
Normal file
@@ -0,0 +1,49 @@
|
||||
---
|
||||
# Check status of all Docker containers
|
||||
- name: Check container status
|
||||
hosts: "{{ target_host | default('all') }}"
|
||||
gather_facts: true
|
||||
|
||||
tasks:
|
||||
- name: Get list of running containers
|
||||
ansible.builtin.command:
|
||||
cmd: docker ps --format "table {{ '{{' }}.Names{{ '}}' }}\t{{ '{{' }}.Status{{ '}}' }}\t{{ '{{' }}.Image{{ '}}' }}"
|
||||
register: docker_ps
|
||||
changed_when: false
|
||||
become: "{{ ansible_become | default(false) }}"
|
||||
|
||||
- name: Display running containers
|
||||
ansible.builtin.debug:
|
||||
msg: |
|
||||
|
||||
=== {{ inventory_hostname }} ===
|
||||
{{ docker_ps.stdout }}
|
||||
|
||||
- name: Get stopped/exited containers
|
||||
ansible.builtin.command:
|
||||
cmd: docker ps -a --filter "status=exited" --format "table {{ '{{' }}.Names{{ '}}' }}\t{{ '{{' }}.Status{{ '}}' }}"
|
||||
register: docker_exited
|
||||
changed_when: false
|
||||
become: "{{ ansible_become | default(false) }}"
|
||||
|
||||
- name: Display stopped containers
|
||||
ansible.builtin.debug:
|
||||
msg: |
|
||||
|
||||
=== Stopped containers on {{ inventory_hostname }} ===
|
||||
{{ docker_exited.stdout }}
|
||||
when: docker_exited.stdout_lines | length > 1
|
||||
|
||||
- name: Get disk usage
|
||||
ansible.builtin.command:
|
||||
cmd: docker system df
|
||||
register: docker_df
|
||||
changed_when: false
|
||||
become: "{{ ansible_become | default(false) }}"
|
||||
|
||||
- name: Display disk usage
|
||||
ansible.builtin.debug:
|
||||
msg: |
|
||||
|
||||
=== Docker disk usage on {{ inventory_hostname }} ===
|
||||
{{ docker_df.stdout }}
|
||||
46
ansible/homelab/playbooks/common/update_containers.yml
Normal file
46
ansible/homelab/playbooks/common/update_containers.yml
Normal file
@@ -0,0 +1,46 @@
|
||||
---
|
||||
# Update all Docker containers (pull new images and recreate)
|
||||
- name: Update Docker containers
|
||||
hosts: "{{ target_host | default('all') }}"
|
||||
gather_facts: true
|
||||
|
||||
vars:
|
||||
services: "{{ host_services | default([]) }}"
|
||||
|
||||
tasks:
|
||||
- name: Display update info
|
||||
ansible.builtin.debug:
|
||||
msg: "Updating {{ services | length }} services on {{ inventory_hostname }}"
|
||||
|
||||
- name: Pull latest images for each service
|
||||
ansible.builtin.command:
|
||||
cmd: docker compose pull
|
||||
chdir: "{{ docker_data_path }}/{{ item.stack_dir }}"
|
||||
loop: "{{ services }}"
|
||||
loop_control:
|
||||
label: "{{ item.name }}"
|
||||
when: item.enabled | default(true)
|
||||
register: pull_result
|
||||
changed_when: "'Downloaded' in pull_result.stdout"
|
||||
failed_when: false
|
||||
become: "{{ ansible_become | default(false) }}"
|
||||
|
||||
- name: Recreate containers with new images
|
||||
ansible.builtin.command:
|
||||
cmd: docker compose up -d --remove-orphans
|
||||
chdir: "{{ docker_data_path }}/{{ item.stack_dir }}"
|
||||
loop: "{{ services }}"
|
||||
loop_control:
|
||||
label: "{{ item.name }}"
|
||||
when: item.enabled | default(true)
|
||||
register: up_result
|
||||
changed_when: "'Started' in up_result.stdout or 'Recreated' in up_result.stdout"
|
||||
failed_when: false
|
||||
become: "{{ ansible_become | default(false) }}"
|
||||
|
||||
- name: Clean up unused images
|
||||
ansible.builtin.command:
|
||||
cmd: docker image prune -af
|
||||
when: prune_images | default(true)
|
||||
changed_when: false
|
||||
become: "{{ ansible_become | default(false) }}"
|
||||
35
ansible/homelab/playbooks/deploy_anubis.yml
Normal file
35
ansible/homelab/playbooks/deploy_anubis.yml
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
# Deployment playbook for anubis
|
||||
# Category: physical
|
||||
# Services: 8
|
||||
#
|
||||
# Usage:
|
||||
# ansible-playbook playbooks/deploy_anubis.yml
|
||||
# ansible-playbook playbooks/deploy_anubis.yml -e "stack_deploy=false"
|
||||
# ansible-playbook playbooks/deploy_anubis.yml --check
|
||||
|
||||
- name: Deploy services to anubis
|
||||
hosts: anubis
|
||||
gather_facts: true
|
||||
vars:
|
||||
services: '{{ host_services | default([]) }}'
|
||||
tasks:
|
||||
- name: Display deployment info
|
||||
ansible.builtin.debug:
|
||||
msg: Deploying {{ services | length }} services to {{ inventory_hostname }}
|
||||
- name: Ensure docker data directory exists
|
||||
ansible.builtin.file:
|
||||
path: '{{ docker_data_path }}'
|
||||
state: directory
|
||||
mode: '0755'
|
||||
- name: Deploy each enabled service
|
||||
ansible.builtin.include_role:
|
||||
name: docker_stack
|
||||
vars:
|
||||
stack_name: '{{ item.stack_dir }}'
|
||||
stack_compose_file: '{{ item.compose_file }}'
|
||||
stack_env_file: '{{ item.env_file | default(omit) }}'
|
||||
loop: '{{ services }}'
|
||||
loop_control:
|
||||
label: '{{ item.name }}'
|
||||
when: item.enabled | default(true)
|
||||
35
ansible/homelab/playbooks/deploy_bulgaria_vm.yml
Normal file
35
ansible/homelab/playbooks/deploy_bulgaria_vm.yml
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
# Deployment playbook for bulgaria-vm
|
||||
# Category: vms
|
||||
# Services: 12
|
||||
#
|
||||
# Usage:
|
||||
# ansible-playbook playbooks/deploy_bulgaria_vm.yml
|
||||
# ansible-playbook playbooks/deploy_bulgaria_vm.yml -e "stack_deploy=false"
|
||||
# ansible-playbook playbooks/deploy_bulgaria_vm.yml --check
|
||||
|
||||
- name: Deploy services to bulgaria-vm
|
||||
hosts: bulgaria_vm
|
||||
gather_facts: true
|
||||
vars:
|
||||
services: '{{ host_services | default([]) }}'
|
||||
tasks:
|
||||
- name: Display deployment info
|
||||
ansible.builtin.debug:
|
||||
msg: Deploying {{ services | length }} services to {{ inventory_hostname }}
|
||||
- name: Ensure docker data directory exists
|
||||
ansible.builtin.file:
|
||||
path: '{{ docker_data_path }}'
|
||||
state: directory
|
||||
mode: '0755'
|
||||
- name: Deploy each enabled service
|
||||
ansible.builtin.include_role:
|
||||
name: docker_stack
|
||||
vars:
|
||||
stack_name: '{{ item.stack_dir }}'
|
||||
stack_compose_file: '{{ item.compose_file }}'
|
||||
stack_env_file: '{{ item.env_file | default(omit) }}'
|
||||
loop: '{{ services }}'
|
||||
loop_control:
|
||||
label: '{{ item.name }}'
|
||||
when: item.enabled | default(true)
|
||||
35
ansible/homelab/playbooks/deploy_chicago_vm.yml
Normal file
35
ansible/homelab/playbooks/deploy_chicago_vm.yml
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
# Deployment playbook for chicago-vm
|
||||
# Category: vms
|
||||
# Services: 7
|
||||
#
|
||||
# Usage:
|
||||
# ansible-playbook playbooks/deploy_chicago_vm.yml
|
||||
# ansible-playbook playbooks/deploy_chicago_vm.yml -e "stack_deploy=false"
|
||||
# ansible-playbook playbooks/deploy_chicago_vm.yml --check
|
||||
|
||||
- name: Deploy services to chicago-vm
|
||||
hosts: chicago_vm
|
||||
gather_facts: true
|
||||
vars:
|
||||
services: '{{ host_services | default([]) }}'
|
||||
tasks:
|
||||
- name: Display deployment info
|
||||
ansible.builtin.debug:
|
||||
msg: Deploying {{ services | length }} services to {{ inventory_hostname }}
|
||||
- name: Ensure docker data directory exists
|
||||
ansible.builtin.file:
|
||||
path: '{{ docker_data_path }}'
|
||||
state: directory
|
||||
mode: '0755'
|
||||
- name: Deploy each enabled service
|
||||
ansible.builtin.include_role:
|
||||
name: docker_stack
|
||||
vars:
|
||||
stack_name: '{{ item.stack_dir }}'
|
||||
stack_compose_file: '{{ item.compose_file }}'
|
||||
stack_env_file: '{{ item.env_file | default(omit) }}'
|
||||
loop: '{{ services }}'
|
||||
loop_control:
|
||||
label: '{{ item.name }}'
|
||||
when: item.enabled | default(true)
|
||||
35
ansible/homelab/playbooks/deploy_concord_nuc.yml
Normal file
35
ansible/homelab/playbooks/deploy_concord_nuc.yml
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
# Deployment playbook for concord-nuc
|
||||
# Category: physical
|
||||
# Services: 15
|
||||
#
|
||||
# Usage:
|
||||
# ansible-playbook playbooks/deploy_concord_nuc.yml
|
||||
# ansible-playbook playbooks/deploy_concord_nuc.yml -e "stack_deploy=false"
|
||||
# ansible-playbook playbooks/deploy_concord_nuc.yml --check
|
||||
|
||||
- name: Deploy services to concord-nuc
|
||||
hosts: concord_nuc
|
||||
gather_facts: true
|
||||
vars:
|
||||
services: '{{ host_services | default([]) }}'
|
||||
tasks:
|
||||
- name: Display deployment info
|
||||
ansible.builtin.debug:
|
||||
msg: Deploying {{ services | length }} services to {{ inventory_hostname }}
|
||||
- name: Ensure docker data directory exists
|
||||
ansible.builtin.file:
|
||||
path: '{{ docker_data_path }}'
|
||||
state: directory
|
||||
mode: '0755'
|
||||
- name: Deploy each enabled service
|
||||
ansible.builtin.include_role:
|
||||
name: docker_stack
|
||||
vars:
|
||||
stack_name: '{{ item.stack_dir }}'
|
||||
stack_compose_file: '{{ item.compose_file }}'
|
||||
stack_env_file: '{{ item.env_file | default(omit) }}'
|
||||
loop: '{{ services }}'
|
||||
loop_control:
|
||||
label: '{{ item.name }}'
|
||||
when: item.enabled | default(true)
|
||||
35
ansible/homelab/playbooks/deploy_contabo_vm.yml
Normal file
35
ansible/homelab/playbooks/deploy_contabo_vm.yml
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
# Deployment playbook for contabo-vm
|
||||
# Category: vms
|
||||
# Services: 1
|
||||
#
|
||||
# Usage:
|
||||
# ansible-playbook playbooks/deploy_contabo_vm.yml
|
||||
# ansible-playbook playbooks/deploy_contabo_vm.yml -e "stack_deploy=false"
|
||||
# ansible-playbook playbooks/deploy_contabo_vm.yml --check
|
||||
|
||||
- name: Deploy services to contabo-vm
|
||||
hosts: contabo_vm
|
||||
gather_facts: true
|
||||
vars:
|
||||
services: '{{ host_services | default([]) }}'
|
||||
tasks:
|
||||
- name: Display deployment info
|
||||
ansible.builtin.debug:
|
||||
msg: Deploying {{ services | length }} services to {{ inventory_hostname }}
|
||||
- name: Ensure docker data directory exists
|
||||
ansible.builtin.file:
|
||||
path: '{{ docker_data_path }}'
|
||||
state: directory
|
||||
mode: '0755'
|
||||
- name: Deploy each enabled service
|
||||
ansible.builtin.include_role:
|
||||
name: docker_stack
|
||||
vars:
|
||||
stack_name: '{{ item.stack_dir }}'
|
||||
stack_compose_file: '{{ item.compose_file }}'
|
||||
stack_env_file: '{{ item.env_file | default(omit) }}'
|
||||
loop: '{{ services }}'
|
||||
loop_control:
|
||||
label: '{{ item.name }}'
|
||||
when: item.enabled | default(true)
|
||||
35
ansible/homelab/playbooks/deploy_guava.yml
Normal file
35
ansible/homelab/playbooks/deploy_guava.yml
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
# Deployment playbook for guava
|
||||
# Category: truenas
|
||||
# Services: 2
|
||||
#
|
||||
# Usage:
|
||||
# ansible-playbook playbooks/deploy_guava.yml
|
||||
# ansible-playbook playbooks/deploy_guava.yml -e "stack_deploy=false"
|
||||
# ansible-playbook playbooks/deploy_guava.yml --check
|
||||
|
||||
- name: Deploy services to guava
|
||||
hosts: guava
|
||||
gather_facts: true
|
||||
vars:
|
||||
services: '{{ host_services | default([]) }}'
|
||||
tasks:
|
||||
- name: Display deployment info
|
||||
ansible.builtin.debug:
|
||||
msg: Deploying {{ services | length }} services to {{ inventory_hostname }}
|
||||
- name: Ensure docker data directory exists
|
||||
ansible.builtin.file:
|
||||
path: '{{ docker_data_path }}'
|
||||
state: directory
|
||||
mode: '0755'
|
||||
- name: Deploy each enabled service
|
||||
ansible.builtin.include_role:
|
||||
name: docker_stack
|
||||
vars:
|
||||
stack_name: '{{ item.stack_dir }}'
|
||||
stack_compose_file: '{{ item.compose_file }}'
|
||||
stack_env_file: '{{ item.env_file | default(omit) }}'
|
||||
loop: '{{ services }}'
|
||||
loop_control:
|
||||
label: '{{ item.name }}'
|
||||
when: item.enabled | default(true)
|
||||
35
ansible/homelab/playbooks/deploy_lxc.yml
Normal file
35
ansible/homelab/playbooks/deploy_lxc.yml
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
# Deployment playbook for lxc
|
||||
# Category: proxmox
|
||||
# Services: 1
|
||||
#
|
||||
# Usage:
|
||||
# ansible-playbook playbooks/deploy_lxc.yml
|
||||
# ansible-playbook playbooks/deploy_lxc.yml -e "stack_deploy=false"
|
||||
# ansible-playbook playbooks/deploy_lxc.yml --check
|
||||
|
||||
- name: Deploy services to lxc
|
||||
hosts: lxc
|
||||
gather_facts: true
|
||||
vars:
|
||||
services: '{{ host_services | default([]) }}'
|
||||
tasks:
|
||||
- name: Display deployment info
|
||||
ansible.builtin.debug:
|
||||
msg: Deploying {{ services | length }} services to {{ inventory_hostname }}
|
||||
- name: Ensure docker data directory exists
|
||||
ansible.builtin.file:
|
||||
path: '{{ docker_data_path }}'
|
||||
state: directory
|
||||
mode: '0755'
|
||||
- name: Deploy each enabled service
|
||||
ansible.builtin.include_role:
|
||||
name: docker_stack
|
||||
vars:
|
||||
stack_name: '{{ item.stack_dir }}'
|
||||
stack_compose_file: '{{ item.compose_file }}'
|
||||
stack_env_file: '{{ item.env_file | default(omit) }}'
|
||||
loop: '{{ services }}'
|
||||
loop_control:
|
||||
label: '{{ item.name }}'
|
||||
when: item.enabled | default(true)
|
||||
35
ansible/homelab/playbooks/deploy_matrix_ubuntu_vm.yml
Normal file
35
ansible/homelab/playbooks/deploy_matrix_ubuntu_vm.yml
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
# Deployment playbook for matrix-ubuntu-vm
|
||||
# Category: vms
|
||||
# Services: 4
|
||||
#
|
||||
# Usage:
|
||||
# ansible-playbook playbooks/deploy_matrix_ubuntu_vm.yml
|
||||
# ansible-playbook playbooks/deploy_matrix_ubuntu_vm.yml -e "stack_deploy=false"
|
||||
# ansible-playbook playbooks/deploy_matrix_ubuntu_vm.yml --check
|
||||
|
||||
- name: Deploy services to matrix-ubuntu-vm
|
||||
hosts: matrix_ubuntu_vm
|
||||
gather_facts: true
|
||||
vars:
|
||||
services: '{{ host_services | default([]) }}'
|
||||
tasks:
|
||||
- name: Display deployment info
|
||||
ansible.builtin.debug:
|
||||
msg: Deploying {{ services | length }} services to {{ inventory_hostname }}
|
||||
- name: Ensure docker data directory exists
|
||||
ansible.builtin.file:
|
||||
path: '{{ docker_data_path }}'
|
||||
state: directory
|
||||
mode: '0755'
|
||||
- name: Deploy each enabled service
|
||||
ansible.builtin.include_role:
|
||||
name: docker_stack
|
||||
vars:
|
||||
stack_name: '{{ item.stack_dir }}'
|
||||
stack_compose_file: '{{ item.compose_file }}'
|
||||
stack_env_file: '{{ item.env_file | default(omit) }}'
|
||||
loop: '{{ services }}'
|
||||
loop_control:
|
||||
label: '{{ item.name }}'
|
||||
when: item.enabled | default(true)
|
||||
35
ansible/homelab/playbooks/deploy_seattle.yml
Normal file
35
ansible/homelab/playbooks/deploy_seattle.yml
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
# Deployment playbook for seattle
|
||||
# Category: vms
|
||||
# Services: 13
|
||||
#
|
||||
# Usage:
|
||||
# ansible-playbook playbooks/deploy_seattle.yml
|
||||
# ansible-playbook playbooks/deploy_seattle.yml -e "stack_deploy=false"
|
||||
# ansible-playbook playbooks/deploy_seattle.yml --check
|
||||
|
||||
- name: Deploy services to seattle
|
||||
hosts: seattle
|
||||
gather_facts: true
|
||||
vars:
|
||||
services: '{{ host_services | default([]) }}'
|
||||
tasks:
|
||||
- name: Display deployment info
|
||||
ansible.builtin.debug:
|
||||
msg: Deploying {{ services | length }} services to {{ inventory_hostname }}
|
||||
- name: Ensure docker data directory exists
|
||||
ansible.builtin.file:
|
||||
path: '{{ docker_data_path }}'
|
||||
state: directory
|
||||
mode: '0755'
|
||||
- name: Deploy each enabled service
|
||||
ansible.builtin.include_role:
|
||||
name: docker_stack
|
||||
vars:
|
||||
stack_name: '{{ item.stack_dir }}'
|
||||
stack_compose_file: '{{ item.compose_file }}'
|
||||
stack_env_file: '{{ item.env_file | default(omit) }}'
|
||||
loop: '{{ services }}'
|
||||
loop_control:
|
||||
label: '{{ item.name }}'
|
||||
when: item.enabled | default(true)
|
||||
87
ansible/homelab/site.yml
Normal file
87
ansible/homelab/site.yml
Normal file
@@ -0,0 +1,87 @@
|
||||
---
|
||||
# Master Homelab Deployment Playbook
|
||||
# Auto-generated from docker-compose files
|
||||
#
|
||||
# Usage:
|
||||
# Deploy everything: ansible-playbook site.yml
|
||||
# Deploy specific host: ansible-playbook site.yml --limit atlantis
|
||||
# Deploy by category: ansible-playbook site.yml --tags synology
|
||||
#
|
||||
|
||||
- name: Deploy all homelab services
|
||||
hosts: localhost
|
||||
gather_facts: false
|
||||
tasks:
|
||||
- name: Display deployment plan
|
||||
ansible.builtin.debug:
|
||||
msg: Deploying services to all hosts. Use --limit to target specific hosts.
|
||||
- name: Deploy to anubis (8 services)
|
||||
ansible.builtin.import_playbook: playbooks/deploy_anubis.yml
|
||||
tags:
|
||||
- physical
|
||||
- anubis
|
||||
- name: Deploy to atlantis (57 services)
|
||||
ansible.builtin.import_playbook: playbooks/deploy_atlantis.yml
|
||||
tags:
|
||||
- synology
|
||||
- atlantis
|
||||
- name: Deploy to bulgaria-vm (12 services)
|
||||
ansible.builtin.import_playbook: playbooks/deploy_bulgaria_vm.yml
|
||||
tags:
|
||||
- vms
|
||||
- bulgaria_vm
|
||||
- name: Deploy to calypso (34 services)
|
||||
ansible.builtin.import_playbook: playbooks/deploy_calypso.yml
|
||||
tags:
|
||||
- synology
|
||||
- calypso
|
||||
- name: Deploy to chicago-vm (7 services)
|
||||
ansible.builtin.import_playbook: playbooks/deploy_chicago_vm.yml
|
||||
tags:
|
||||
- vms
|
||||
- chicago_vm
|
||||
- name: Deploy to concord-nuc (15 services)
|
||||
ansible.builtin.import_playbook: playbooks/deploy_concord_nuc.yml
|
||||
tags:
|
||||
- physical
|
||||
- concord_nuc
|
||||
- name: Deploy to contabo-vm (1 services)
|
||||
ansible.builtin.import_playbook: playbooks/deploy_contabo_vm.yml
|
||||
tags:
|
||||
- vms
|
||||
- contabo_vm
|
||||
- name: Deploy to guava (2 services)
|
||||
ansible.builtin.import_playbook: playbooks/deploy_guava.yml
|
||||
tags:
|
||||
- truenas
|
||||
- guava
|
||||
- name: Deploy to homelab-vm (39 services)
|
||||
ansible.builtin.import_playbook: playbooks/deploy_homelab_vm.yml
|
||||
tags:
|
||||
- vms
|
||||
- homelab_vm
|
||||
- name: Deploy to lxc (1 services)
|
||||
ansible.builtin.import_playbook: playbooks/deploy_lxc.yml
|
||||
tags:
|
||||
- proxmox
|
||||
- lxc
|
||||
- name: Deploy to matrix-ubuntu-vm (4 services)
|
||||
ansible.builtin.import_playbook: playbooks/deploy_matrix_ubuntu_vm.yml
|
||||
tags:
|
||||
- vms
|
||||
- matrix_ubuntu_vm
|
||||
- name: Deploy to rpi5-vish (6 services)
|
||||
ansible.builtin.import_playbook: playbooks/deploy_rpi5_vish.yml
|
||||
tags:
|
||||
- edge
|
||||
- rpi5_vish
|
||||
- name: Deploy to seattle (13 services)
|
||||
ansible.builtin.import_playbook: playbooks/deploy_seattle.yml
|
||||
tags:
|
||||
- vms
|
||||
- seattle
|
||||
- name: Deploy to setillo (5 services)
|
||||
ansible.builtin.import_playbook: playbooks/deploy_setillo.yml
|
||||
tags:
|
||||
- synology
|
||||
- setillo
|
||||
Reference in New Issue
Block a user