feat: add Ansible playbook and roles for deploying AI Tutor on Proxmox VM
This commit is contained in:
parent
3242383508
commit
69e6f43eef
16
ansible/playbooks/deploy-aitutor-vm.yml
Normal file
16
ansible/playbooks/deploy-aitutor-vm.yml
Normal 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
|
||||||
7
ansible/roles/aitutor_install/defaults/main.yml
Normal file
7
ansible/roles/aitutor_install/defaults/main.yml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
aitutor_npm_package: "@aitutor/cli"
|
||||||
|
aitutor_npm_version: "latest"
|
||||||
|
aitutor_extra_packages:
|
||||||
|
- nodejs
|
||||||
|
- npm
|
||||||
|
- ca-certificates
|
||||||
28
ansible/roles/aitutor_install/tasks/main.yml
Normal file
28
ansible/roles/aitutor_install/tasks/main.yml
Normal 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 }}"
|
||||||
32
ansible/roles/proxmox_vm_deploy/defaults/main.yml
Normal file
32
ansible/roles/proxmox_vm_deploy/defaults/main.yml
Normal 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
|
||||||
114
ansible/roles/proxmox_vm_deploy/tasks/main.yml
Normal file
114
ansible/roles/proxmox_vm_deploy/tasks/main.yml
Normal 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
|
||||||
Loading…
x
Reference in New Issue
Block a user