Update onboard-nodes.yml to target physical_servers and add ai-p410 to hosts.ini so onboarding limits no longer skip that host.
This commit is contained in:
parent
92c8125981
commit
9a749a8c97
@ -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
|
|
||||||
@ -31,6 +31,7 @@ pve01 ansible_host=10.0.0.201 ansible_user=root
|
|||||||
[physical_servers]
|
[physical_servers]
|
||||||
heimdall ansible_host=10.0.0.151 ansible_user=chester
|
heimdall ansible_host=10.0.0.151 ansible_user=chester
|
||||||
waldorf ansible_host=10.0.0.251 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]
|
[raspberry_pi]
|
||||||
watchtower ansible_host=10.0.0.200 ansible_user=chester
|
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]
|
[nfs_clients]
|
||||||
heimdall ansible_host=10.0.0.151 ansible_user=chester
|
heimdall ansible_host=10.0.0.151 ansible_user=chester
|
||||||
waldorf ansible_host=10.0.0.251 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
|
# Group Variables
|
||||||
|
|||||||
@ -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.
|
|
||||||
@ -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
|
|
||||||
@ -5,7 +5,7 @@
|
|||||||
# (-k prompts for SSH password, -K prompts for sudo password)
|
# (-k prompts for SSH password, -K prompts for sudo password)
|
||||||
|
|
||||||
- name: Onboard new nodes to Ansible control
|
- name: Onboard new nodes to Ansible control
|
||||||
hosts: heimdall,waldorf
|
hosts: physical_servers
|
||||||
gather_facts: true
|
gather_facts: true
|
||||||
become: false
|
become: false
|
||||||
tasks:
|
tasks:
|
||||||
|
|||||||
@ -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
|
|
||||||
@ -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
|
|
||||||
@ -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
|
|
||||||
@ -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
|
|
||||||
@ -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
|
|
||||||
@ -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
|
|
||||||
@ -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
|
|
||||||
@ -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
|
|
||||||
@ -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
|
|
||||||
@ -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
|
|
||||||
@ -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 %}
|
|
||||||
@ -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
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
{% for key, value in openapply_app_spa_env.items() %}
|
|
||||||
{{ key }}={{ value }}
|
|
||||||
{% endfor %}
|
|
||||||
@ -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"
|
|
||||||
Loading…
x
Reference in New Issue
Block a user