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