ilia 69a39e5e5b Add POTE app project support and improve IP conflict detection (#3)
## Summary

This PR adds comprehensive support for deploying the **POTE** application project via Ansible, along with improvements to IP conflict detection and a new app stack provisioning system for Proxmox-managed LXC containers.

## Key Features

### 🆕 New Roles
- **`roles/pote`**: Python/venv deployment role for POTE (PostgreSQL, cron jobs, Alembic migrations)
- **`roles/app_setup`**: Generic app deployment role (Node.js/systemd)
- **`roles/base_os`**: Base OS hardening role

### 🛡️ Safety Improvements
- IP uniqueness validation within projects
- Proxmox-side IP conflict detection
- Enhanced error messages for IP conflicts

### 📦 New Playbooks
- `playbooks/app/site.yml`: End-to-end app stack deployment
- `playbooks/app/provision_vms.yml`: Proxmox guest provisioning
- `playbooks/app/configure_app.yml`: OS + application configuration

## Security
-  All secrets stored in encrypted vault.yml
-  Deploy keys excluded via .gitignore
-  No plaintext secrets committed

## Testing
-  POTE successfully deployed to dev/qa/prod environments
-  All components validated (Git, PostgreSQL, cron, migrations)

Co-authored-by: ilia <ilia@levkin.ca>
Reviewed-on: #3
2026-01-01 11:19:54 -05:00

117 lines
4.1 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
# Role: pote
# Purpose: Deploy POTE (Python/venv + cron) from a Git repo via SSH.
# -----------------------------------------------------------------------------
# Git / source
# -----------------------------------------------------------------------------
pote_git_repo: ""
pote_git_branch: "main"
# SSH private key used to clone/pull (vault-backed). Keep this secret.
# Prefer setting `vault_pote_git_ssh_key` in your vault; `vault_git_ssh_key` is supported for compatibility.
pote_git_ssh_key: "{{ vault_pote_git_ssh_key | default(vault_git_ssh_key | default('')) }}"
# Host/IP for known_hosts (so first clone is non-interactive).
pote_git_host: "10.0.30.169"
pote_git_port: 22
# -----------------------------------------------------------------------------
# User / paths
# -----------------------------------------------------------------------------
pote_user: "poteapp"
pote_group: "{{ pote_user }}"
pote_app_dir: "/home/{{ pote_user }}/pote"
pote_venv_dir: "{{ pote_app_dir }}/venv"
pote_python_bin: "python3.11"
# Environment file
pote_env_file: "{{ pote_app_dir }}/.env"
pote_env_file_mode: "0600"
# Logs
pote_logs_dir: "/home/{{ pote_user }}/logs"
pote_log_level: "INFO"
pote_log_file: "{{ pote_logs_dir }}/pote.log"
# Monitoring / alerting (optional)
pote_market_tickers: ""
pote_alert_min_severity: ""
# Optional API keys
pote_quiverquant_api_key: ""
pote_fmp_api_key: ""
# -----------------------------------------------------------------------------
# System deps
# -----------------------------------------------------------------------------
pote_system_packages:
- git
- ca-certificates
- python3.11
- python3.11-venv
- python3.11-dev
- python3-pip
- build-essential
- postgresql
- postgresql-contrib
- postgresql-client
- libpq-dev
# -----------------------------------------------------------------------------
# Database
# -----------------------------------------------------------------------------
pote_db_host: "localhost"
pote_db_port: 5432
pote_db_name: "potedb"
pote_db_user: "poteuser"
# Prefer env-specific vault vars; fall back to a generic one if present.
pote_db_password: >-
{{
vault_pote_db_password
| default(
(vault_pote_db_password_dev | default(vault_db_password_dev | default(''), true)) if pote_env == 'dev'
else (vault_pote_db_password_qa | default(vault_db_password_qa | default(''), true)) if pote_env == 'qa'
else (vault_pote_db_password_prod | default(vault_db_password_prod | default(''), true)) if pote_env == 'prod'
else '',
true
)
}}
# Convenience computed URL (commonly used by Python apps)
pote_database_url: "postgresql://{{ pote_db_user }}:{{ pote_db_password }}@{{ pote_db_host }}:{{ pote_db_port }}/{{ pote_db_name }}"
# -----------------------------------------------------------------------------
# SMTP / email
# -----------------------------------------------------------------------------
pote_smtp_host: "mail.levkin.ca"
pote_smtp_port: 587
pote_smtp_user: ""
pote_smtp_password: "{{ vault_pote_smtp_password | default(vault_smtp_password | default('')) }}"
pote_from_email: ""
pote_report_recipients: ""
# -----------------------------------------------------------------------------
# Automation / cron
# -----------------------------------------------------------------------------
pote_enable_cron: true
# "minute hour" (e.g. "0 6")
pote_daily_report_time: "0 6"
# "minute hour dow" (e.g. "0 8 0" => Sunday 08:00)
pote_weekly_report_time: "0 8 0"
# "minute hour" for */6 style (e.g. "0 */6")
pote_health_check_time: "0 */6"
pote_daily_report_enabled: true
pote_weekly_report_enabled: true
pote_health_check_enabled: true
# Commands (adjust to your repos actual scripts)
pote_daily_job: "{{ pote_app_dir }}/scripts/automated_daily_run.sh >> {{ pote_logs_dir }}/daily_run.log 2>&1"
pote_weekly_job: "{{ pote_app_dir }}/scripts/automated_weekly_run.sh >> {{ pote_logs_dir }}/weekly_run.log 2>&1"
pote_health_check_job: "{{ pote_venv_dir }}/bin/python {{ pote_app_dir }}/scripts/health_check.py >> {{ pote_logs_dir }}/health_check.log 2>&1"
# Environment name for templating/logging (dev|qa|prod)
pote_env: "{{ app_env | default('prod') }}"