feat: add Ansible playbook and roles for deploying AI Tutor on Proxmox VM

This commit is contained in:
nathan 2026-04-21 21:16:03 -04:00
parent 3242383508
commit 69e6f43eef
5 changed files with 197 additions and 0 deletions

View File

@ -0,0 +1,16 @@
---
- name: Provision VM on Proxmox for AI Tutor
hosts: localhost
gather_facts: false
connection: local
roles:
- role: proxmox_vm_deploy
- name: Install AI Tutor on provisioned VM
hosts: aitutor_vm
gather_facts: true
become: true
roles:
- role: aitutor_install

View File

@ -0,0 +1,7 @@
---
aitutor_npm_package: "@aitutor/cli"
aitutor_npm_version: "latest"
aitutor_extra_packages:
- nodejs
- npm
- ca-certificates

View File

@ -0,0 +1,28 @@
---
- name: Ensure supported OS family
ansible.builtin.assert:
that:
- ansible_os_family == 'Debian'
fail_msg: "This role currently supports Debian-family distributions only."
- name: Install runtime packages for AI Tutor
ansible.builtin.apt:
name: "{{ aitutor_extra_packages }}"
state: present
update_cache: true
- name: Install or update AI Tutor CLI globally via npm
community.general.npm:
name: "{{ aitutor_npm_package }}"
version: "{{ aitutor_npm_version }}"
global: true
state: present
- name: Verify aitutor command is available
ansible.builtin.command: which aitutor
register: aitutor_bin
changed_when: false
- name: Show installed aitutor path
ansible.builtin.debug:
msg: "AITutor installed at {{ aitutor_bin.stdout }}"

View File

@ -0,0 +1,32 @@
---
# Proxmox API endpoint and auth
proxmox_api_host: "10.0.0.201"
proxmox_api_user: "ansible@pve"
proxmox_api_token_id: "ansible"
proxmox_api_token_secret: "SET_IN_VAULT"
proxmox_validate_certs: false
# VM placement
proxmox_node: "pve01"
proxmox_vmid: 9210
proxmox_vm_name: "aitutor"
proxmox_template: "ubuntu-2404-cloudinit-template"
proxmox_storage: "local-lvm"
# VM sizing
proxmox_cores: 2
proxmox_memory_mb: 4096
proxmox_disk_gb: 32
# Network and cloud-init
proxmox_bridge: "vmbr0"
vm_ipconfig0: "ip=10.0.0.210/24,gw=10.0.0.2"
vm_nameserver: "10.0.0.2"
vm_searchdomain: "lan"
vm_ci_user: "chester"
vm_ci_password: "SET_IN_VAULT"
vm_ssh_public_key: ""
vm_ssh_private_key_file: "~/.ssh/id_ed25519"
# Timing
vm_boot_timeout_seconds: 300

View File

@ -0,0 +1,114 @@
---
- name: Validate required Proxmox variables
ansible.builtin.assert:
that:
- proxmox_api_host | length > 0
- proxmox_api_user | length > 0
- proxmox_api_token_id | length > 0
- proxmox_api_token_secret | length > 0
- proxmox_node | length > 0
- proxmox_template | length > 0
- proxmox_vmid | int > 99
- vm_ci_user | length > 0
- vm_ipconfig0 is match('^ip=.+')
fail_msg: "Missing required VM provisioning variables."
- name: Gather current VMs on Proxmox node
community.proxmox.proxmox_vm_info:
api_host: "{{ proxmox_api_host }}"
api_user: "{{ proxmox_api_user }}"
api_token_id: "{{ proxmox_api_token_id }}"
api_token_secret: "{{ proxmox_api_token_secret }}"
validate_certs: "{{ proxmox_validate_certs }}"
node: "{{ proxmox_node }}"
register: proxmox_vms
- name: Detect whether target VM already exists
ansible.builtin.set_fact:
vm_exists: >-
{{
(proxmox_vms.proxmox_vms | default([])
| selectattr('vmid', 'equalto', proxmox_vmid | int)
| list
| length) > 0
}}
- name: Clone VM from cloud-init template when missing
community.proxmox.proxmox_kvm:
api_host: "{{ proxmox_api_host }}"
api_user: "{{ proxmox_api_user }}"
api_token_id: "{{ proxmox_api_token_id }}"
api_token_secret: "{{ proxmox_api_token_secret }}"
validate_certs: "{{ proxmox_validate_certs }}"
node: "{{ proxmox_node }}"
clone: "{{ proxmox_template }}"
newid: "{{ proxmox_vmid }}"
name: "{{ proxmox_vm_name }}"
storage: "{{ proxmox_storage }}"
full: true
timeout: 600
state: present
when: not vm_exists
- name: Apply VM hardware, network, and cloud-init settings
community.proxmox.proxmox_kvm:
api_host: "{{ proxmox_api_host }}"
api_user: "{{ proxmox_api_user }}"
api_token_id: "{{ proxmox_api_token_id }}"
api_token_secret: "{{ proxmox_api_token_secret }}"
validate_certs: "{{ proxmox_validate_certs }}"
node: "{{ proxmox_node }}"
vmid: "{{ proxmox_vmid }}"
name: "{{ proxmox_vm_name }}"
cores: "{{ proxmox_cores }}"
memory: "{{ proxmox_memory_mb }}"
scsihw: virtio-scsi-pci
scsi:
scsi0: "{{ proxmox_storage }}:{{ proxmox_disk_gb }}"
net:
net0: "virtio,bridge={{ proxmox_bridge }}"
ciuser: "{{ vm_ci_user }}"
cipassword: "{{ vm_ci_password }}"
ipconfig:
ipconfig0: "{{ vm_ipconfig0 }}"
nameservers:
- "{{ vm_nameserver }}"
searchdomains:
- "{{ vm_searchdomain }}"
sshkeys: "{{ vm_ssh_public_key | default(omit) }}"
onboot: true
agent: true
update: true
state: present
- name: Ensure VM is running
community.proxmox.proxmox_kvm:
api_host: "{{ proxmox_api_host }}"
api_user: "{{ proxmox_api_user }}"
api_token_id: "{{ proxmox_api_token_id }}"
api_token_secret: "{{ proxmox_api_token_secret }}"
validate_certs: "{{ proxmox_validate_certs }}"
node: "{{ proxmox_node }}"
vmid: "{{ proxmox_vmid }}"
state: started
- name: Derive VM IPv4 address from cloud-init ipconfig
ansible.builtin.set_fact:
vm_ipv4: "{{ (vm_ipconfig0.split('ip=')[1].split(',')[0]).split('/')[0] }}"
- name: Wait for SSH on provisioned VM
ansible.builtin.wait_for:
host: "{{ vm_ipv4 }}"
port: 22
timeout: "{{ vm_boot_timeout_seconds }}"
delay: 5
delegate_to: localhost
- name: Add new VM to in-memory inventory
ansible.builtin.add_host:
name: "{{ proxmox_vm_name }}"
groups: aitutor_vm
ansible_host: "{{ vm_ipv4 }}"
ansible_user: "{{ vm_ci_user }}"
ansible_ssh_private_key_file: "{{ vm_ssh_private_key_file }}"
ansible_python_interpreter: /usr/bin/python3