From 9a749a8c97f6570db9086ba601d7c56102eecc69 Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 21 Apr 2026 11:44:00 -0400 Subject: [PATCH] Update onboard-nodes.yml to target physical_servers and add ai-p410 to hosts.ini so onboarding limits no longer skip that host. --- ansible/group_vars/all/openapply.yml | 42 ----- ansible/inventory/hosts.ini | 2 + .../playbooks/OPENAPPLY-VAULT-REFERENCE.md | 128 --------------- ansible/playbooks/deploy-openapply.yml | 126 --------------- ansible/playbooks/onboard-nodes.yml | 2 +- ansible/roles/openapply_app/README.md | 98 ------------ ansible/roles/openapply_app/defaults/main.yml | 52 ------ ansible/roles/openapply_app/handlers/main.yml | 9 -- ansible/roles/openapply_app/meta/main.yml | 27 ---- .../roles/openapply_app/tasks/deploy_code.yml | 148 ------------------ ansible/roles/openapply_app/tasks/main.yml | 15 -- ansible/roles/openapply_app/tasks/prereqs.yml | 37 ----- .../roles/openapply_app/tasks/setup_env.yml | 42 ----- .../roles/openapply_app/tasks/validate.yml | 31 ---- ansible/roles/openapply_app/tasks/verify.yml | 23 --- .../openapply_app/templates/openapply.env.j2 | 6 - .../templates/openapply.service.j2 | 19 --- .../templates/openapply.spa.env.j2 | 3 - ansible/roles/openapply_app/vars/main.yml | 3 - 19 files changed, 3 insertions(+), 810 deletions(-) delete mode 100644 ansible/group_vars/all/openapply.yml delete mode 100644 ansible/playbooks/OPENAPPLY-VAULT-REFERENCE.md delete mode 100644 ansible/playbooks/deploy-openapply.yml delete mode 100644 ansible/roles/openapply_app/README.md delete mode 100644 ansible/roles/openapply_app/defaults/main.yml delete mode 100644 ansible/roles/openapply_app/handlers/main.yml delete mode 100644 ansible/roles/openapply_app/meta/main.yml delete mode 100644 ansible/roles/openapply_app/tasks/deploy_code.yml delete mode 100644 ansible/roles/openapply_app/tasks/main.yml delete mode 100644 ansible/roles/openapply_app/tasks/prereqs.yml delete mode 100644 ansible/roles/openapply_app/tasks/setup_env.yml delete mode 100644 ansible/roles/openapply_app/tasks/validate.yml delete mode 100644 ansible/roles/openapply_app/tasks/verify.yml delete mode 100644 ansible/roles/openapply_app/templates/openapply.env.j2 delete mode 100644 ansible/roles/openapply_app/templates/openapply.service.j2 delete mode 100644 ansible/roles/openapply_app/templates/openapply.spa.env.j2 delete mode 100644 ansible/roles/openapply_app/vars/main.yml diff --git a/ansible/group_vars/all/openapply.yml b/ansible/group_vars/all/openapply.yml deleted file mode 100644 index 51f61e8..0000000 --- a/ansible/group_vars/all/openapply.yml +++ /dev/null @@ -1,42 +0,0 @@ ---- -# Proxmox API settings (credentials come from vault variables) -openapply_pve_api_host: "{{ vault_proxmox_api_host | default('10.0.0.201') }}" -openapply_pve_api_user: "{{ vault_proxmox_api_user | default('root@pam') }}" -openapply_pve_api_token_id: "{{ vault_proxmox_api_token_id | default('automation', true) }}" -openapply_pve_api_token_secret: "{{ vault_proxmox_api_token_secret | default('') }}" -openapply_proxmox_validate_certs: false - -# Proxmox target and LXC specification -openapply_pve_node: pve01 -openapply_lxc_vmid: 105 -openapply_lxc_hostname: openapply-prod -openapply_lxc_template: local:vztmpl/ubuntu-24.04-standard_24.04-2_amd64.tar.zst -openapply_lxc_storage: local-lvm -openapply_lxc_cores: 2 -openapply_lxc_memory_mb: 4096 -openapply_lxc_swap_mb: 512 -openapply_lxc_unprivileged: true -openapply_lxc_onboot: true -openapply_lxc_features: - - nesting=1 - -# LXC networking -openapply_lxc_bridge: vmbr0 -openapply_lxc_ip_cidr: 10.0.0.105/24 -openapply_lxc_gateway: 10.0.0.2 -openapply_lxc_management_ip: 10.0.0.105 -openapply_lxc_ssh_user: root -openapply_lxc_ssh_port: 22 -openapply_lxc_nic_firewall: true -openapply_use_proxmox_nic: false - -# LXC credentials (from vault) -openapply_lxc_password: "{{ vault_openapply_lxc_root_password | default(vault_proxmox_root_password | default('')) }}" - -# Controller runtime preflight -openapply_validate_controller_python_deps: true - -# Application runtime toggles for first deployment -openapply_app_install_firebase_cli: false -openapply_app_repo_version: master -openapply_app_force_rebuild: true diff --git a/ansible/inventory/hosts.ini b/ansible/inventory/hosts.ini index ad5874a..1690718 100644 --- a/ansible/inventory/hosts.ini +++ b/ansible/inventory/hosts.ini @@ -31,6 +31,7 @@ pve01 ansible_host=10.0.0.201 ansible_user=root [physical_servers] heimdall ansible_host=10.0.0.151 ansible_user=chester waldorf ansible_host=10.0.0.251 ansible_user=chester +ai-p410 ansible_host=10.0.0.202 ansible_user=chester [raspberry_pi] watchtower ansible_host=10.0.0.200 ansible_user=chester @@ -41,6 +42,7 @@ watchtower ansible_host=10.0.0.200 ansible_user=chester [nfs_clients] heimdall ansible_host=10.0.0.151 ansible_user=chester waldorf ansible_host=10.0.0.251 ansible_user=chester +ai-p410 ansible_host=10.0.0.202 ansible_user=chester # ============================================================================= # Group Variables diff --git a/ansible/playbooks/OPENAPPLY-VAULT-REFERENCE.md b/ansible/playbooks/OPENAPPLY-VAULT-REFERENCE.md deleted file mode 100644 index df40b69..0000000 --- a/ansible/playbooks/OPENAPPLY-VAULT-REFERENCE.md +++ /dev/null @@ -1,128 +0,0 @@ -# OpenApply Deployment - Vault Variables Reference - -This document lists the encrypted variables that must be configured in `ansible/group_vars/all/vault.yml` before deploying OpenApply. - -## Required Vault Variables - -### Proxmox API Authentication - -```yaml -# Proxmox API endpoint -vault_proxmox_api_host: "10.0.0.201" - -# Proxmox API user (typically root@pam) -vault_proxmox_api_user: "root@pam" - -# Proxmox API token ID -vault_proxmox_api_token_id: "automation" - -# Proxmox API token secret (encrypted) -vault_proxmox_api_token_secret: !vault | - $ANSIBLE_VAULT;1.1;AES256 - [encrypted token here] -``` - -### LXC Container Credentials - -```yaml -# Root password for the OpenApply LXC container (encrypted) -vault_openapply_lxc_root_password: !vault | - $ANSIBLE_VAULT;1.1;AES256 - [encrypted password here] -``` - -### Application Secrets (Optional) - -```yaml -# Firebase deployment token (optional, encrypted) -vault_openapply_firebase_token: !vault | - $ANSIBLE_VAULT;1.1;AES256 - [encrypted token here] -``` - -### SPA Firebase Configuration (Required for non-blank /app UI) - -```yaml -# Public Firebase client config used at SPA build-time -vault_openapply_firebase_api_key: "AIza..." -vault_openapply_firebase_auth_domain: "your-project.firebaseapp.com" -vault_openapply_firebase_project_id: "your-project-id" -vault_openapply_firebase_storage_bucket: "your-project.appspot.com" -vault_openapply_firebase_messaging_sender_id: "1234567890" -vault_openapply_firebase_app_id: "1:1234567890:web:abcdef123456" - -# Optional UX/admin metadata -vault_openapply_admin_email: "admin@your-domain.tld" -vault_openapply_support_email: "support@your-domain.tld" -``` - -## Creating/Editing Vault Variables - -### First-time Setup - -```bash -# Navigate to ansible directory -cd /home/chester/homelab/ansible - -# Edit the encrypted vault file -ansible-vault edit group_vars/all/vault.yml - -# Add the variables listed above -``` - -### Generating a Proxmox API Token - -1. Log into Proxmox web UI (https://pve01:8006) -2. Navigate to: Datacenter → Permissions → API Tokens -3. Click "Add" button -4. User: `root@pam` -5. Token ID: `automation` (or custom name) -6. Privilege Separation: **Unchecked** (for full root@pam permissions) -7. Click "Add" -8. **Copy the secret immediately** (only shown once) -9. Add to vault file as shown above - -### Required Permissions - -If using privilege separation, the token needs: -- `VM.Allocate` - Create new containers -- `VM.Config.Network` - Configure networking -- `VM.PowerMgmt` - Start/stop containers -- `Datastore.AllocateSpace` - Allocate storage - -### Security Best Practices - -1. **Never commit unencrypted secrets** to Git -2. Rotate API tokens quarterly -3. Use separate tokens for different automation workflows -4. Audit Proxmox API access logs regularly -5. Verify vault encryption: `ansible-vault view group_vars/all/vault.yml` - -## Validation - -Test that vault variables are correctly configured: - -```bash -# Verify vault can be decrypted -ansible-vault view group_vars/all/vault.yml - -# Test variable resolution (without execution) -ansible-playbook playbooks/deploy-openapply.yml --check --diff -``` - -## Troubleshooting - -### "vault_proxmox_api_token_secret is undefined" - -Ensure the variable is present in `group_vars/all/vault.yml` and the file is properly encrypted. - -### "Authentication failed" - -1. Verify token ID matches Proxmox configuration -2. Confirm token is not expired -3. Check privilege separation settings -4. Regenerate token if necessary - -### "Cannot decrypt vault" - -Ensure `ansible/vault/.vault_pass` contains the correct vault password. diff --git a/ansible/playbooks/deploy-openapply.yml b/ansible/playbooks/deploy-openapply.yml deleted file mode 100644 index ad85c56..0000000 --- a/ansible/playbooks/deploy-openapply.yml +++ /dev/null @@ -1,126 +0,0 @@ ---- -- name: Provision OpenApply LXC on Proxmox - hosts: localhost - gather_facts: false - connection: local - become: false - - pre_tasks: - - name: Validate required infrastructure variables - ansible.builtin.assert: - that: - - openapply_pve_api_host | length > 0 - - openapply_pve_api_user | length > 0 - - openapply_pve_api_token_id | length > 0 - - openapply_pve_api_token_secret | length > 0 - - openapply_pve_node | length > 0 - - openapply_lxc_vmid | int > 0 - - openapply_lxc_hostname | length > 0 - - openapply_lxc_template | length > 0 - - openapply_lxc_storage | length > 0 - - openapply_lxc_ip_cidr | length > 0 - - openapply_lxc_gateway | length > 0 - - openapply_lxc_management_ip | length > 0 - - openapply_lxc_password | length > 0 - fail_msg: >- - Required Proxmox/OpenApply LXC variables are missing. Check - group_vars/all/openapply.yml and vault variables. - - - name: Validate Proxmox Python dependencies on controller - ansible.builtin.command: "{{ ansible_playbook_python }} -c 'import proxmoxer, requests'" - register: openapply_controller_python_deps - changed_when: false - failed_when: openapply_controller_python_deps.rc != 0 - become: false - when: openapply_validate_controller_python_deps | bool - - tasks: - - name: Ensure OpenApply LXC is present - community.proxmox.proxmox: - api_host: "{{ openapply_pve_api_host }}" - api_user: "{{ openapply_pve_api_user }}" - api_token_id: "{{ openapply_pve_api_token_id }}" - api_token_secret: "{{ openapply_pve_api_token_secret }}" - validate_certs: "{{ openapply_proxmox_validate_certs }}" - node: "{{ openapply_pve_node }}" - vmid: "{{ openapply_lxc_vmid }}" - hostname: "{{ openapply_lxc_hostname }}" - ostemplate: "{{ openapply_lxc_template }}" - storage: "{{ openapply_lxc_storage }}" - cores: "{{ openapply_lxc_cores }}" - memory: "{{ openapply_lxc_memory_mb }}" - swap: "{{ openapply_lxc_swap_mb }}" - password: "{{ openapply_lxc_password }}" - onboot: "{{ openapply_lxc_onboot }}" - unprivileged: "{{ openapply_lxc_unprivileged }}" - netif: - net0: "name=eth0,bridge={{ openapply_lxc_bridge }},ip={{ openapply_lxc_ip_cidr }},gw={{ openapply_lxc_gateway }}" - features: "{{ openapply_lxc_features }}" - state: present - register: openapply_lxc_status - - - name: Ensure OpenApply LXC is started - community.proxmox.proxmox: - api_host: "{{ openapply_pve_api_host }}" - api_user: "{{ openapply_pve_api_user }}" - api_token_id: "{{ openapply_pve_api_token_id }}" - api_token_secret: "{{ openapply_pve_api_token_secret }}" - validate_certs: "{{ openapply_proxmox_validate_certs }}" - node: "{{ openapply_pve_node }}" - vmid: "{{ openapply_lxc_vmid }}" - state: started - - - name: Reconcile LXC NIC configuration via Proxmox API - when: openapply_use_proxmox_nic | bool - block: - - name: Ensure net0 configuration through proxmox_nic - community.proxmox.proxmox_nic: - api_host: "{{ openapply_pve_api_host }}" - api_user: "{{ openapply_pve_api_user }}" - api_token_id: "{{ openapply_pve_api_token_id }}" - api_token_secret: "{{ openapply_pve_api_token_secret }}" - validate_certs: "{{ openapply_proxmox_validate_certs }}" - vmid: "{{ openapply_lxc_vmid }}" - name: "{{ openapply_lxc_hostname }}" - interface: net0 - bridge: "{{ openapply_lxc_bridge }}" - firewall: "{{ openapply_lxc_nic_firewall }}" - state: present - rescue: - - name: Continue when proxmox_nic is unsupported for this target - ansible.builtin.debug: - msg: >- - proxmox_nic could not be applied to vmid {{ openapply_lxc_vmid }}; - continuing with proxmox container network configuration only. - - - name: Add OpenApply LXC to runtime inventory - ansible.builtin.add_host: - name: "{{ openapply_lxc_hostname }}" - ansible_host: "{{ openapply_lxc_management_ip }}" - ansible_user: "{{ openapply_lxc_ssh_user }}" - ansible_port: "{{ openapply_lxc_ssh_port }}" - ansible_password: "{{ openapply_lxc_password }}" - ansible_ssh_pass: "{{ openapply_lxc_password }}" - ansible_python_interpreter: /usr/bin/python3 - groups: lxc_guests - - - name: Display provisioning summary - ansible.builtin.debug: - msg: - - "LXC hostname: {{ openapply_lxc_hostname }}" - - "LXC management IP: {{ openapply_lxc_management_ip }}" - - "LXC vmid: {{ openapply_lxc_vmid }}" - - "LXC changed: {{ openapply_lxc_status.changed | default(false) }}" - -- name: Configure OpenApply application inside guest - hosts: lxc_guests - gather_facts: true - become: true - - pre_tasks: - - name: Wait for SSH connectivity to LXC guest - ansible.builtin.wait_for_connection: - timeout: 300 - - roles: - - role: openapply_app diff --git a/ansible/playbooks/onboard-nodes.yml b/ansible/playbooks/onboard-nodes.yml index c59e3bc..d86a02f 100644 --- a/ansible/playbooks/onboard-nodes.yml +++ b/ansible/playbooks/onboard-nodes.yml @@ -5,7 +5,7 @@ # (-k prompts for SSH password, -K prompts for sudo password) - name: Onboard new nodes to Ansible control - hosts: heimdall,waldorf + hosts: physical_servers gather_facts: true become: false tasks: diff --git a/ansible/roles/openapply_app/README.md b/ansible/roles/openapply_app/README.md deleted file mode 100644 index 737ec86..0000000 --- a/ansible/roles/openapply_app/README.md +++ /dev/null @@ -1,98 +0,0 @@ -# openapply_app - -Ansible role to deploy the OpenApply application stack (Vue.js/Astro/Firebase) to an Ubuntu LXC guest. - -## Description - -This role configures an Ubuntu 22.04/24.04 LXC container to run the OpenApply web application in production mode. It handles: - -- Node.js 20+ runtime installation via NodeSource -- pnpm package manager setup -- Firebase CLI installation (optional) -- UFW firewall configuration (production ports only: 22, 80, 443) -- Git-based source deployment -- Systemd service configuration and lifecycle management -- Application build process for Astro and SPA components -- HTTP health validation - -## Requirements - -- Target OS: Ubuntu 22.04 (Jammy) or 24.04 (Noble) -- Minimum Ansible: 2.16 -- Collections: - - `community.general >= 8.0.0` - - `ansible.posix >= 1.5.0` - -## Role Variables - -### Application Settings - -| Variable | Default | Description | -|----------|---------|-------------| -| `openapply_app_repo_url` | `https://github.com/sergeykhval/openapply.git` | Git repository URL | -| `openapply_app_repo_version` | `main` | Git branch/tag/commit | -| `openapply_app_root` | `/opt/openapply` | Application install path | -| `openapply_app_service_name` | `openapply` | Systemd service name | -| `openapply_app_service_user` | `openapply` | Service runtime user | -| `openapply_app_service_group` | `openapply` | Service runtime group | -| `openapply_app_service_port` | `80` | HTTP listen port | - -### Runtime Configuration - -| Variable | Default | Description | -|----------|---------|-------------| -| `openapply_app_node_major` | `"20"` | Node.js major version | -| `openapply_app_install_firebase_cli` | `true` | Install Firebase CLI globally | -| `openapply_app_build_subdirs` | `["astro", "spa"]` | Subdirectories to build | -| `openapply_app_force_rebuild` | `false` | Force rebuild on every run | - -### Network & Security - -| Variable | Default | Description | -|----------|---------|-------------| -| `openapply_app_enable_firewall` | `true` | Enable UFW firewall | -| `openapply_app_allowed_tcp_ports` | `[22, 80, 443]` | Allowed TCP ports | - -### Secrets - -| Variable | Default | Description | -|----------|---------|-------------| -| `openapply_app_firebase_token` | `{{ vault_openapply_firebase_token \| default('') }}` | Firebase deployment token | - -## Dependencies - -None. - -## Example Playbook - -```yaml -- name: Deploy OpenApply application - hosts: openapply_lxc_guest - become: true - roles: - - role: openapply_app - vars: - openapply_app_repo_version: "v1.2.3" - openapply_app_service_port: 8080 -``` - -## Example with Proxmox Provisioning - -See `playbooks/deploy-openapply.yml` for a complete two-tier workflow that: -1. Provisions an LXC container on Proxmox -2. Deploys and configures OpenApply inside the guest - -## License - -MIT - -## Author - -Created by FrankGPT for the homelab infrastructure automation project. - -## Notes - -- **Production-only mode**: Dev ports (3000, 5173) are not exposed by default -- **Git clone strategy**: Application code is cloned fresh on first run, then updated on subsequent runs -- **Build idempotency**: Builds are triggered only when repo changes or `openapply_app_force_rebuild` is set -- **Systemd lifecycle**: Service is managed via systemd with automatic restart on failure diff --git a/ansible/roles/openapply_app/defaults/main.yml b/ansible/roles/openapply_app/defaults/main.yml deleted file mode 100644 index 6cd05b0..0000000 --- a/ansible/roles/openapply_app/defaults/main.yml +++ /dev/null @@ -1,52 +0,0 @@ ---- -openapply_app_repo_url: https://github.com/sergeykhval/openapply.git -openapply_app_repo_version: main - -openapply_app_service_name: openapply -openapply_app_service_user: openapply -openapply_app_service_group: openapply - -openapply_app_root: /opt/openapply -openapply_app_service_port: 80 - -openapply_app_node_major: "20" -openapply_app_install_firebase_cli: true - -openapply_app_enable_firewall: true -openapply_app_allowed_tcp_ports: - - 22 - - 80 - - 443 - -openapply_app_build_subdirs: - - astro - - spa - -openapply_app_force_rebuild: false -openapply_app_git_ssh_key_file: "" - -openapply_app_start_command: >- - pnpm --dir {{ openapply_app_root }}/astro preview --host 0.0.0.0 --port {{ openapply_app_service_port }} - -openapply_app_env: - NODE_ENV: production - PORT: "{{ openapply_app_service_port }}" - -openapply_app_spa_env: - VITE_BASE_URL: /app - VITE_FIREBASE_API_KEY: "{{ vault_openapply_firebase_api_key | default('your-firebase-api-key') }}" - VITE_FIREBASE_AUTH_DOMAIN: "{{ vault_openapply_firebase_auth_domain | default('your-project.firebaseapp.com') }}" - VITE_FIREBASE_PROJECT_ID: "{{ vault_openapply_firebase_project_id | default('your-project-id') }}" - VITE_FIREBASE_STORAGE_BUCKET: "{{ vault_openapply_firebase_storage_bucket | default('your-project.appspot.com') }}" - VITE_FIREBASE_MESSAGING_SENDER_ID: "{{ vault_openapply_firebase_messaging_sender_id | default('your-sender-id') }}" - VITE_FIREBASE_APP_ID: "{{ vault_openapply_firebase_app_id | default('your-app-id') }}" - VITE_ADMIN_EMAIL: "{{ vault_openapply_admin_email | default('admin@example.com') }}" - VITE_SUPPORT_EMAIL: "{{ vault_openapply_support_email | default('support@example.com') }}" - -openapply_app_require_real_firebase_config: true - -openapply_app_firebase_token: "{{ vault_openapply_firebase_token | default('') }}" -openapply_app_verify_status_codes: - - 200 - - 301 - - 302 diff --git a/ansible/roles/openapply_app/handlers/main.yml b/ansible/roles/openapply_app/handlers/main.yml deleted file mode 100644 index 3114924..0000000 --- a/ansible/roles/openapply_app/handlers/main.yml +++ /dev/null @@ -1,9 +0,0 @@ ---- -- name: Reload systemd - ansible.builtin.systemd: - daemon_reload: true - -- name: Restart OpenApply service - ansible.builtin.systemd: - name: "{{ openapply_app_service_name }}" - state: restarted diff --git a/ansible/roles/openapply_app/meta/main.yml b/ansible/roles/openapply_app/meta/main.yml deleted file mode 100644 index 53776f3..0000000 --- a/ansible/roles/openapply_app/meta/main.yml +++ /dev/null @@ -1,27 +0,0 @@ ---- -galaxy_info: - role_name: openapply_app - namespace: homelab - author: FrankGPT - description: Deploy OpenApply application stack (Vue/Astro/Firebase) to Ubuntu LXC guest - license: MIT - min_ansible_version: "2.16" - - platforms: - - name: Ubuntu - versions: - - jammy - - noble - - galaxy_tags: - - web - - nodejs - - application - - deployment - - lxc - -dependencies: [] - -collections: - - community.general - - ansible.posix diff --git a/ansible/roles/openapply_app/tasks/deploy_code.yml b/ansible/roles/openapply_app/tasks/deploy_code.yml deleted file mode 100644 index a3fccc1..0000000 --- a/ansible/roles/openapply_app/tasks/deploy_code.yml +++ /dev/null @@ -1,148 +0,0 @@ ---- -- name: Ensure OpenApply group exists - ansible.builtin.group: - name: "{{ openapply_app_service_group }}" - state: present - -- name: Ensure OpenApply service user exists - ansible.builtin.user: - name: "{{ openapply_app_service_user }}" - group: "{{ openapply_app_service_group }}" - home: /home/{{ openapply_app_service_user }} - shell: /usr/sbin/nologin - create_home: true - system: true - state: present - -- name: Ensure OpenApply root directory exists - ansible.builtin.file: - path: "{{ openapply_app_root }}" - state: directory - owner: "{{ openapply_app_service_user }}" - group: "{{ openapply_app_service_group }}" - mode: "0755" - -- name: Check whether OpenApply directory is already a git repository - ansible.builtin.stat: - path: "{{ openapply_app_root }}/.git" - register: openapply_git_metadata - -- name: Reset OpenApply directory when not a git repository - ansible.builtin.file: - path: "{{ openapply_app_root }}" - state: absent - when: not openapply_git_metadata.stat.exists - -- name: Recreate OpenApply root directory after reset - ansible.builtin.file: - path: "{{ openapply_app_root }}" - state: directory - owner: "{{ openapply_app_service_user }}" - group: "{{ openapply_app_service_group }}" - mode: "0755" - when: not openapply_git_metadata.stat.exists - -- name: Sync OpenApply source code - ansible.builtin.git: - repo: "{{ openapply_app_repo_url }}" - version: "{{ openapply_app_repo_version }}" - dest: "{{ openapply_app_root }}" - update: true - force: true - accept_hostkey: true - key_file: "{{ openapply_app_git_ssh_key_file | default(omit, true) }}" - become: true - become_user: "{{ openapply_app_service_user }}" - register: openapply_repo_checkout - -- name: Render OpenApply environment file - ansible.builtin.template: - src: openapply.env.j2 - dest: "{{ openapply_app_root }}/.env" - owner: "{{ openapply_app_service_user }}" - group: "{{ openapply_app_service_group }}" - mode: "0640" - -- name: Render OpenApply SPA build environment file - ansible.builtin.template: - src: openapply.spa.env.j2 - dest: "{{ openapply_app_root }}/spa/.env" - owner: "{{ openapply_app_service_user }}" - group: "{{ openapply_app_service_group }}" - mode: "0640" - -- name: Check node_modules presence - ansible.builtin.stat: - path: "{{ openapply_app_root }}/node_modules" - register: openapply_node_modules - -- name: Install OpenApply dependencies via pnpm - ansible.builtin.command: - cmd: pnpm install --frozen-lockfile - chdir: "{{ openapply_app_root }}" - become: true - become_user: "{{ openapply_app_service_user }}" - when: - - openapply_repo_checkout.changed or openapply_app_force_rebuild | bool or not openapply_node_modules.stat.exists - changed_when: true - -- name: Check which build directories exist - ansible.builtin.stat: - path: "{{ openapply_app_root }}/{{ item }}" - register: openapply_build_dir_stats - loop: "{{ openapply_app_build_subdirs }}" - -- name: Build OpenApply subprojects - ansible.builtin.command: - cmd: pnpm run build - chdir: "{{ openapply_app_root }}/{{ item.item }}" - become: true - become_user: "{{ openapply_app_service_user }}" - loop: "{{ openapply_build_dir_stats.results }}" - when: - - item.stat.exists - - openapply_repo_checkout.changed or openapply_app_force_rebuild | bool - changed_when: true - -- name: Check Astro dist directory - ansible.builtin.stat: - path: "{{ openapply_app_root }}/astro/dist" - register: openapply_astro_dist - -- name: Check SPA dist directory - ansible.builtin.stat: - path: "{{ openapply_app_root }}/spa/dist" - register: openapply_spa_dist - -- name: Publish SPA build under /app path for Astro runtime - ansible.builtin.shell: | - rm -rf "{{ openapply_app_root }}/astro/dist/app" - mkdir -p "{{ openapply_app_root }}/astro/dist/app" - cp -a "{{ openapply_app_root }}/spa/dist/." "{{ openapply_app_root }}/astro/dist/app/" - args: - executable: /bin/bash - become: true - become_user: "{{ openapply_app_service_user }}" - when: - - openapply_astro_dist.stat.isdir | default(false) - - openapply_spa_dist.stat.isdir | default(false) - - openapply_repo_checkout.changed or openapply_app_force_rebuild | bool - changed_when: true - -- name: Install OpenApply systemd unit - ansible.builtin.template: - src: openapply.service.j2 - dest: "/etc/systemd/system/{{ openapply_app_service_name }}.service" - owner: root - group: root - mode: "0644" - notify: - - Reload systemd - - Restart OpenApply service - -- name: Ensure OpenApply service is enabled and started - ansible.builtin.systemd: - name: "{{ openapply_app_service_name }}" - enabled: true - state: started - daemon_reload: true diff --git a/ansible/roles/openapply_app/tasks/main.yml b/ansible/roles/openapply_app/tasks/main.yml deleted file mode 100644 index 7d28286..0000000 --- a/ansible/roles/openapply_app/tasks/main.yml +++ /dev/null @@ -1,15 +0,0 @@ ---- -- name: Validate role input - ansible.builtin.import_tasks: validate.yml - -- name: Install base prerequisites - ansible.builtin.import_tasks: prereqs.yml - -- name: Configure runtime dependencies - ansible.builtin.import_tasks: setup_env.yml - -- name: Deploy and build OpenApply - ansible.builtin.import_tasks: deploy_code.yml - -- name: Verify running service - ansible.builtin.import_tasks: verify.yml diff --git a/ansible/roles/openapply_app/tasks/prereqs.yml b/ansible/roles/openapply_app/tasks/prereqs.yml deleted file mode 100644 index 81f6a4c..0000000 --- a/ansible/roles/openapply_app/tasks/prereqs.yml +++ /dev/null @@ -1,37 +0,0 @@ ---- -- name: Install OpenApply prerequisite packages - ansible.builtin.apt: - name: - - ca-certificates - - curl - - git - - gnupg - - ufw - - build-essential - state: present - update_cache: true - cache_valid_time: 3600 - -- name: Configure UFW for production web access - when: openapply_app_enable_firewall | bool - block: - - name: Set default incoming firewall policy - community.general.ufw: - direction: incoming - default: deny - - - name: Set default outgoing firewall policy - community.general.ufw: - direction: outgoing - default: allow - - - name: Allow required TCP ports - community.general.ufw: - rule: allow - port: "{{ item }}" - proto: tcp - loop: "{{ openapply_app_allowed_tcp_ports }}" - - - name: Enable UFW - community.general.ufw: - state: enabled diff --git a/ansible/roles/openapply_app/tasks/setup_env.yml b/ansible/roles/openapply_app/tasks/setup_env.yml deleted file mode 100644 index 575c0ad..0000000 --- a/ansible/roles/openapply_app/tasks/setup_env.yml +++ /dev/null @@ -1,42 +0,0 @@ ---- -- name: Ensure apt keyrings directory exists - ansible.builtin.file: - path: /etc/apt/keyrings - state: directory - mode: "0755" - -- name: Download NodeSource signing key - ansible.builtin.get_url: - url: https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key - dest: /tmp/nodesource.gpg.key - mode: "0644" - -- name: Install NodeSource keyring - ansible.builtin.command: - cmd: gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg /tmp/nodesource.gpg.key - creates: /etc/apt/keyrings/nodesource.gpg - -- name: Add NodeSource apt repository - ansible.builtin.apt_repository: - repo: "{{ openapply_app_nodesource_repo_map[ansible_os_family] }}" - filename: nodesource - state: present - -- name: Install Node.js runtime - ansible.builtin.apt: - name: nodejs - state: present - update_cache: true - -- name: Install pnpm globally - community.general.npm: - name: pnpm - global: true - state: present - -- name: Install Firebase CLI globally - community.general.npm: - name: firebase-tools - global: true - state: present - when: openapply_app_install_firebase_cli | bool diff --git a/ansible/roles/openapply_app/tasks/validate.yml b/ansible/roles/openapply_app/tasks/validate.yml deleted file mode 100644 index d7b54c9..0000000 --- a/ansible/roles/openapply_app/tasks/validate.yml +++ /dev/null @@ -1,31 +0,0 @@ ---- -- name: Ensure guest OS family is supported - ansible.builtin.assert: - that: - - ansible_os_family == "Debian" - fail_msg: "openapply_app currently supports Debian-family guests (Ubuntu 22.04/24.04)." - -- name: Ensure required role variables are present - ansible.builtin.assert: - that: - - openapply_app_repo_url | length > 0 - - openapply_app_repo_version | length > 0 - - openapply_app_root | length > 0 - - openapply_app_service_name | length > 0 - - openapply_app_service_user | length > 0 - - openapply_app_start_command | length > 0 - fail_msg: "Required OpenApply role variables are missing." - -- name: Ensure real Firebase SPA configuration is provided - ansible.builtin.assert: - that: - - openapply_app_spa_env.VITE_FIREBASE_API_KEY != 'your-firebase-api-key' - - openapply_app_spa_env.VITE_FIREBASE_AUTH_DOMAIN != 'your-project.firebaseapp.com' - - openapply_app_spa_env.VITE_FIREBASE_PROJECT_ID != 'your-project-id' - - openapply_app_spa_env.VITE_FIREBASE_STORAGE_BUCKET != 'your-project.appspot.com' - - openapply_app_spa_env.VITE_FIREBASE_MESSAGING_SENDER_ID != 'your-sender-id' - - openapply_app_spa_env.VITE_FIREBASE_APP_ID != 'your-app-id' - fail_msg: >- - OpenApply SPA is using placeholder Firebase values. Set vault_openapply_firebase_* variables - in group_vars/all/vault.yml, then redeploy. - when: openapply_app_require_real_firebase_config | bool diff --git a/ansible/roles/openapply_app/tasks/verify.yml b/ansible/roles/openapply_app/tasks/verify.yml deleted file mode 100644 index 1afa98b..0000000 --- a/ansible/roles/openapply_app/tasks/verify.yml +++ /dev/null @@ -1,23 +0,0 @@ ---- -- name: Verify OpenApply service reaches active state - ansible.builtin.command: - cmd: "systemctl is-active {{ openapply_app_service_name }}" - register: openapply_service_state - changed_when: false - retries: 20 - delay: 3 - until: openapply_service_state.stdout | trim == 'active' - -- name: Wait for OpenApply port to become reachable - ansible.builtin.wait_for: - host: 127.0.0.1 - port: "{{ openapply_app_service_port }}" - timeout: 120 - -- name: Validate HTTP response from OpenApply endpoint - ansible.builtin.uri: - url: "http://127.0.0.1:{{ openapply_app_service_port }}/" - method: GET - status_code: "{{ openapply_app_verify_status_codes }}" - register: openapply_http_probe - changed_when: false diff --git a/ansible/roles/openapply_app/templates/openapply.env.j2 b/ansible/roles/openapply_app/templates/openapply.env.j2 deleted file mode 100644 index aaa2d24..0000000 --- a/ansible/roles/openapply_app/templates/openapply.env.j2 +++ /dev/null @@ -1,6 +0,0 @@ -{% for key, value in openapply_app_env.items() %} -{{ key }}={{ value }} -{% endfor %} -{% if openapply_app_firebase_token | length > 0 %} -FIREBASE_TOKEN={{ openapply_app_firebase_token }} -{% endif %} diff --git a/ansible/roles/openapply_app/templates/openapply.service.j2 b/ansible/roles/openapply_app/templates/openapply.service.j2 deleted file mode 100644 index 0124ab1..0000000 --- a/ansible/roles/openapply_app/templates/openapply.service.j2 +++ /dev/null @@ -1,19 +0,0 @@ -[Unit] -Description=OpenApply web service -Wants=network-online.target -After=network-online.target - -[Service] -Type=simple -User={{ openapply_app_service_user }} -Group={{ openapply_app_service_group }} -WorkingDirectory={{ openapply_app_root }} -EnvironmentFile={{ openapply_app_root }}/.env -ExecStart={{ openapply_app_start_command }} -AmbientCapabilities=CAP_NET_BIND_SERVICE -CapabilityBoundingSet=CAP_NET_BIND_SERVICE -Restart=on-failure -RestartSec=3 - -[Install] -WantedBy=multi-user.target diff --git a/ansible/roles/openapply_app/templates/openapply.spa.env.j2 b/ansible/roles/openapply_app/templates/openapply.spa.env.j2 deleted file mode 100644 index 22ad996..0000000 --- a/ansible/roles/openapply_app/templates/openapply.spa.env.j2 +++ /dev/null @@ -1,3 +0,0 @@ -{% for key, value in openapply_app_spa_env.items() %} -{{ key }}={{ value }} -{% endfor %} diff --git a/ansible/roles/openapply_app/vars/main.yml b/ansible/roles/openapply_app/vars/main.yml deleted file mode 100644 index 53f96f8..0000000 --- a/ansible/roles/openapply_app/vars/main.yml +++ /dev/null @@ -1,3 +0,0 @@ ---- -openapply_app_nodesource_repo_map: - Debian: "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_{{ openapply_app_node_major }}.x nodistro main"