# Ansible Playbooks for VM Configuration

Ansible playbooks for post-deployment configuration of Proxmox VMs.

## 📋 Available Playbooks

### Foundation Playbooks

| Playbook | Description | What It Does |
|----------|-------------|--------------|
| `base-config` | Base system configuration | Hostname, timezone, locale, system updates, essential packages |
| `users` | User management | Creates users with SSH keys and sudo access |

### Application Playbooks

| Playbook | Description | What It Does |
|----------|-------------|--------------|
| `nginx` | Web server | Installs Nginx, creates default site, configures firewall |
| `postgresql` | Database server | Installs PostgreSQL (auto-detects version), creates databases/users |
| `mysql` | MySQL/MariaDB database | Installs MariaDB with remote access, creates databases/users, configures firewall |
| `mssql` | Microsoft SQL Server | Installs MSSQL Server with remote access (Ubuntu 20/22/24, RHEL/Rocky 9 only, 4GB RAM min) |
| `mongodb` | MongoDB database | Installs MongoDB, configures bind IP and port |
| `docker-compose` | Docker platform | Ensures Docker running, installs Docker Compose, adds users to docker group |
| `k3s` | Kubernetes cluster | Installs k3s single-node cluster, kubectl, Helm, configures kubeconfig access |

### Operations Playbooks

| Playbook | Description | What It Does |
|----------|-------------|--------------|
| `monitoring` | Metrics collection | Installs Prometheus Node Exporter on port 9100 |

## 🚀 Usage

### From Menu (Recommended)

```bash
./build-template.sh
→ Deploy VM from Template
→ Select playbooks (SPACE to select multiple)
```

### Manual Execution

```bash
cd ansible/

# Single playbook
ansible-playbook -i VM_IP, playbooks/nginx.yml

# Multiple playbooks
ansible-playbook -i VM_IP, playbooks/base-config.yml
ansible-playbook -i VM_IP, playbooks/nginx.yml
ansible-playbook -i VM_IP, playbooks/monitoring.yml
```

## 🎯 Common Combinations

**Web Server:**
```bash
base-config nginx monitoring
```

**Database Server:**
```bash
base-config postgresql monitoring
# or
base-config mysql monitoring
# or
base-config mssql monitoring  # Ubuntu 20/22/24 or Rocky/AlmaLinux 9 only
# or
base-config mongodb monitoring
```

**Docker Host:**
```bash
base-config docker-compose monitoring
```

**Kubernetes Node:**
```bash
base-config k3s monitoring
```

**Development Server:**
```bash
base-config users nginx mysql docker-compose monitoring
# or with PostgreSQL:
base-config users nginx postgresql docker-compose monitoring
```

## ⚙️ Configuration

### Override Variables

Create `vars/custom.yml`:

```yaml
---
# Nginx configuration
nginx_port: 8080
nginx_server_name: myapp.example.com

# PostgreSQL configuration
postgresql_listen_addresses: "*"
postgresql_databases:
  - name: myapp
    owner: myapp_user
postgresql_users:
  - name: myapp_user
    password: "changeme123"

# MySQL/MariaDB configuration
mysql_bind_address: "0.0.0.0"
mysql_databases:
  - name: myapp
    encoding: utf8mb4
mysql_users:
  - name: myapp_user
    password: "changeme123"
    host: "%"  # Allow from any host
    priv: "myapp.*:ALL"

# MSSQL configuration
mssql_accept_eula: true
mssql_sa_password: "YourStrong!Passw0rd"
mssql_edition: "Developer"  # or Express
mssql_databases:
  - name: MyAppDB
mssql_logins:
  - name: myapp_user
    password: "StrongPass123!"
    database: MyAppDB
    roles: ["db_owner"]

# MongoDB configuration
mongodb_bind_ip: "0.0.0.0"
mongodb_port: 27017

# User management
system_users:
  - name: jdoe
    first_name: John
    last_name: Doe
    ssh_key: "ssh-rsa AAAA..."
```

Use with:
```bash
ansible-playbook -i VM_IP, -e @vars/custom.yml playbooks/nginx.yml
```

### Custom Playbooks

Add your own to `playbooks/`:

```yaml
---
- name: My Custom Application
  hosts: all
  become: yes

  tasks:
    - name: Install application
      package:
        name: myapp
        state: present
```

## 📝 Playbook Details

### base-config

**Variables:**
- `system_timezone`: Default `UTC`
- `system_locale`: Default `en_US.UTF-8`
- `system_hostname`: Auto-set from VM name

**Packages installed:**
- Essential: vim, curl, wget, git
- Network: net-tools, dnsutils
- Archive: unzip, tar
- System: htop, ncdu

### users

**Variables:**
```yaml
system_users:
  - name: username
    first_name: "First"
    last_name: "Last"
    ssh_key: "ssh-rsa AAAA..."  # Optional
    sudo: true  # Optional, default false
```

**Creates:**
- User account with home directory
- SSH authorized_keys if provided
- Sudo access if requested

### nginx

**Variables:**
- `nginx_port`: Default `80`
- `nginx_server_name`: Default `{{ inventory_hostname }}`

**Creates:**
- Default website at `/var/www/html`
- Firewall rule for HTTP/HTTPS

### postgresql

**Auto-detects version:**
- Ubuntu 24.04 → PostgreSQL 16
- Ubuntu 22.04 → PostgreSQL 14
- Rocky/AlmaLinux → Latest available

**Variables:**
```yaml
postgresql_listen_addresses: "localhost"  # "*" for all
postgresql_databases:
  - name: mydb
    owner: myuser
postgresql_users:
  - name: myuser
    password: "secret"
```

### mysql

**Installs MariaDB** (MySQL-compatible, fully open-source)

**Variables:**
```yaml
mysql_bind_address: "0.0.0.0"  # Remote access enabled by default
mysql_port: 3306
mysql_max_connections: 151
mysql_root_password: ""  # Empty = unix_socket auth (secure)
mysql_databases:
  - name: mydb
    encoding: utf8mb4
    collation: utf8mb4_unicode_ci
mysql_users:
  - name: myuser
    password: "secret123"
    host: "%"  # % = any host, or specify IP/hostname
    priv: "mydb.*:ALL"  # Grant privileges on mydb
```

**Security Features:**
- Root remote login disabled
- Anonymous users removed
- Test database removed
- Firewall port 3306 opened (if remote access enabled)
- Unix socket authentication for root (no password needed locally)

**Connection:**
```bash
# Local (as root)
mysql -u root

# Remote
mysql -h SERVER_IP -u myuser -p
```

### mssql

**Installs Microsoft SQL Server 2022** for Linux

**⚠️ System Requirements:**
- **RAM:** Minimum 2 GB, **recommend 4 GB** for production
- **Disk:** Minimum 6 GB free space
- **Distributions:** Ubuntu 20.04/22.04/24.04, RHEL 9, Rocky 9, AlmaLinux 9 ONLY
- **Architecture:** x86_64 only
- **Download:** ~700 MB (large package)

**Variables:**
```yaml
mssql_accept_eula: true  # REQUIRED: Accept Microsoft EULA
mssql_sa_password: "YourStrong!Passw0rd"  # REQUIRED: 8+ chars, mixed case, digits, symbols
mssql_edition: "Developer"  # Developer (free, non-prod) or Express (free, 10GB limit)
mssql_tcp_port: 1433
mssql_memory_limit_mb: 2048
mssql_enable_agent: true
mssql_databases:
  - name: MyAppDB
mssql_logins:
  - name: myapp_user
    password: "StrongPass123!"
    database: MyAppDB
    roles: ["db_owner", "db_datareader", "db_datawriter"]
```

**Editions:**
- **Developer:** Free, full features, NON-PRODUCTION use only
- **Express:** Free, 10 GB database limit, 1 GB RAM limit, production OK
- **Standard/Enterprise:** Commercial license required

**Security Features:**
- Remote access enabled (port 1433)
- SA password required (complexity enforced)
- Firewall port 1433 opened automatically
- Tools added to system PATH

**Connection:**
```bash
# Local
sqlcmd -S localhost -U SA -P 'YourPassword'

# Remote
sqlcmd -S SERVER_IP -U SA -P 'YourPassword'

# JDBC connection string
jdbc:sqlserver://SERVER_IP:1433;databaseName=MyAppDB;user=myapp_user;password=StrongPass123!
```

**Commands:**
```bash
# Query databases
sqlcmd -S localhost -U SA -P 'Password' -Q "SELECT name FROM sys.databases"

# Interactive session
sqlcmd -S localhost -U SA -P 'Password'
1> USE MyAppDB;
2> GO
1> SELECT * FROM sys.tables;
2> GO
1> EXIT
```

**Important Notes:**
- ⚠️ Playbook will **FAIL** on unsupported distributions (Fedora, openSUSE, Debian)
- ⚠️ Playbook will **FAIL** if RAM < 2 GB
- ⚠️ Installation takes 5-10 minutes (large download)
- ⚠️ SA password must meet complexity requirements
- 💡 Developer edition for development/testing
- 💡 Express edition for small production databases

### mongodb

**Variables:**
- `mongodb_bind_ip`: Default `127.0.0.1`
- `mongodb_port`: Default `27017`

### docker-compose

**Variables:**
- `docker_users`: Default `["admin"]`

**Creates:**
- `/opt/docker-compose` directory for projects
- Adds specified users to docker group

### k3s

**Installs k3s single-node Kubernetes cluster** (lightweight Kubernetes distribution)

**Variables:**
```yaml
k3s_version: "latest"  # or specify version like "v1.28.5+k3s1"
k3s_channel: "stable"  # stable, latest, or testing

k3s_server_args:
  - "--write-kubeconfig-mode=644"
  - "--disable=traefik"  # Optional: disable traefik
  # - "--disable=servicelb"  # Optional: disable service LB
  # - "--cluster-cidr=10.42.0.0/16"
  # - "--service-cidr=10.43.0.0/16"

k3s_group: "k3s-users"  # Group with kubeconfig access
kubectl_alias: "k"  # Alias for kubectl command
```

**What it installs:**
- k3s server (single-node cluster)
- kubectl (Kubernetes CLI)
- Helm 3 (Kubernetes package manager)
- Bash completion for kubectl and helm

**Configuration:**
- Kubeconfig file: `/etc/rancher/k3s/k3s.yaml`
- Admin user from cloud-init added to `k3s-users` group
- kubectl and helm in system PATH
- Environment variables set in `/etc/profile.d/k3s.sh`

**Post-installation:**
```bash
# Users must log out/in or run:
source /etc/profile.d/k3s.sh

# Verify cluster
kubectl cluster-info
kubectl get nodes

# Deploy test application
kubectl create deployment nginx --image=nginx
kubectl expose deployment nginx --port=80 --type=NodePort
kubectl get svc nginx
```

**Usage instructions:**
After installation, find detailed usage at `/root/k3s-usage.txt`

**Uninstall:**
```bash
/usr/local/bin/k3s-uninstall.sh
```

**See also:** https://docs.k3s.io/installation/configuration

### monitoring

**Variables:**
- `node_exporter_version`: Default `1.7.0`
- `node_exporter_port`: Default `9100`

**Exposes:**
- Metrics at `http://VM_IP:9100/metrics`

## 🐛 Troubleshooting

### Connection Issues

```bash
# Test connectivity
ansible all -i VM_IP, -m ping

# Use specific user
ansible-playbook -i VM_IP, -u root playbooks/nginx.yml

# Increase verbosity
ansible-playbook -i VM_IP, -vvv playbooks/nginx.yml
```

### Playbook Failures

**Check SSH access:**
```bash
ssh admin@VM_IP
```

**View logs:**
```bash
tail -f /linux_automation/logs/ansible-*.log
```

**Dry run:**
```bash
ansible-playbook -i VM_IP, --check playbooks/nginx.yml
```

### Common Issues

| Error | Cause | Solution |
|-------|-------|----------|
| "No package matching 'postgresql-14'" | Wrong PostgreSQL version | Update to latest playbook (auto-detects) |
| "Authentication failed" | Wrong password | Check `config/defaults.conf` |
| "Connection timeout" | VM not ready | Wait 30s, check SSH port open |
| "Permission denied" | No sudo access | User needs sudo privileges |

## 🔧 Requirements

- Ansible 2.9+
- Python 3.6+ on target VMs
- SSH access to VMs
- `admin` user with sudo privileges (or root)

## 📚 Resources

**Ansible Documentation:**
- [Playbooks Guide](https://docs.ansible.com/ansible/latest/user_guide/playbooks.html)
- [Module Index](https://docs.ansible.com/ansible/latest/modules/modules_by_category.html)

**Customization:**
- Edit playbooks in `playbooks/`
- Add variables in `vars/`
- Templates in `templates/`

## 💡 Tips

1. **Always run base-config first** - Sets up hostname, timezone, updates
2. **Use --check for dry runs** - Preview changes before applying
3. **Group related playbooks** - Deploy web stack together
4. **Version control your custom playbooks** - Track changes
5. **Test on one VM first** - Before applying to production
6. **Check logs for errors** - Located in `/linux_automation/logs/ansible-*.log`

---

**Note:** Playbooks are designed to be idempotent - safe to run multiple times without causing issues.
