379 lines
8.4 KiB
Markdown
379 lines
8.4 KiB
Markdown
# Proxmox API Reference
|
|
|
|
## Overview
|
|
|
|
The Proxmox API enables programmatic management of the cluster via REST. This reference focuses on common patterns for Python (proxmoxer) and Terraform/Ansible usage.
|
|
|
|
## Authentication Methods
|
|
|
|
### API Tokens (Recommended)
|
|
|
|
**Create API token via CLI:**
|
|
|
|
```bash
|
|
pveum user token add <user>@<realm> <token-id> --privsep 0
|
|
```
|
|
|
|
**Environment variables:**
|
|
|
|
```bash
|
|
export PROXMOX_VE_API_TOKEN="user@realm!token-id=secret"
|
|
export PROXMOX_VE_ENDPOINT="https://192.168.3.5:8006"
|
|
```
|
|
|
|
### Password Authentication
|
|
|
|
```bash
|
|
export PROXMOX_VE_USERNAME="root@pam"
|
|
export PROXMOX_VE_PASSWORD="password"
|
|
export PROXMOX_VE_ENDPOINT="https://192.168.3.5:8006"
|
|
```
|
|
|
|
## Python API Usage (proxmoxer)
|
|
|
|
### Installation
|
|
|
|
```bash
|
|
# Using uv inline script metadata
|
|
# /// script
|
|
# dependencies = ["proxmoxer", "requests"]
|
|
# ///
|
|
```
|
|
|
|
### Basic Connection
|
|
|
|
```python
|
|
#!/usr/bin/env python3
|
|
# /// script
|
|
# dependencies = ["proxmoxer", "requests"]
|
|
# ///
|
|
|
|
from proxmoxer import ProxmoxAPI
|
|
import os
|
|
|
|
# Connect using API token
|
|
proxmox = ProxmoxAPI(
|
|
os.getenv("PROXMOX_VE_ENDPOINT").replace("https://", "").replace(":8006", ""),
|
|
user=os.getenv("PROXMOX_VE_USERNAME"),
|
|
token_name=os.getenv("PROXMOX_VE_TOKEN_NAME"),
|
|
token_value=os.getenv("PROXMOX_VE_TOKEN_VALUE"),
|
|
verify_ssl=False
|
|
)
|
|
|
|
# OR using password
|
|
proxmox = ProxmoxAPI(
|
|
'192.168.3.5',
|
|
user='root@pam',
|
|
password=os.getenv("PROXMOX_VE_PASSWORD"),
|
|
verify_ssl=False
|
|
)
|
|
```
|
|
|
|
### Common Operations
|
|
|
|
**List VMs:**
|
|
|
|
```python
|
|
# Get all VMs across cluster
|
|
for node in proxmox.nodes.get():
|
|
node_name = node['node']
|
|
for vm in proxmox.nodes(node_name).qemu.get():
|
|
print(f"VM {vm['vmid']}: {vm['name']} on {node_name} - {vm['status']}")
|
|
```
|
|
|
|
**Get VM Configuration:**
|
|
|
|
```python
|
|
vmid = 101
|
|
node = "foxtrot"
|
|
|
|
vm_config = proxmox.nodes(node).qemu(vmid).config.get()
|
|
print(f"VM {vmid} config: {vm_config}")
|
|
```
|
|
|
|
**Clone Template:**
|
|
|
|
```python
|
|
template_id = 9000
|
|
new_vmid = 101
|
|
node = "foxtrot"
|
|
|
|
# Clone template
|
|
proxmox.nodes(node).qemu(template_id).clone.post(
|
|
newid=new_vmid,
|
|
name="docker-01-nexus",
|
|
full=1, # Full clone (not linked)
|
|
storage="local-lvm"
|
|
)
|
|
|
|
# Wait for clone to complete
|
|
import time
|
|
while True:
|
|
tasks = proxmox.nodes(node).tasks.get()
|
|
clone_task = next((t for t in tasks if t['type'] == 'qmclone' and str(t['id']) == str(new_vmid)), None)
|
|
if not clone_task or clone_task['status'] == 'stopped':
|
|
break
|
|
time.sleep(2)
|
|
```
|
|
|
|
**Update VM Configuration:**
|
|
|
|
```python
|
|
# Set cloud-init parameters
|
|
proxmox.nodes(node).qemu(vmid).config.put(
|
|
ipconfig0="ip=192.168.3.100/24,gw=192.168.3.1",
|
|
nameserver="192.168.3.1",
|
|
searchdomain="spaceships.work",
|
|
sshkeys="ssh-rsa AAAA..."
|
|
)
|
|
```
|
|
|
|
**Start/Stop VM:**
|
|
|
|
```python
|
|
# Start VM
|
|
proxmox.nodes(node).qemu(vmid).status.start.post()
|
|
|
|
# Stop VM (graceful)
|
|
proxmox.nodes(node).qemu(vmid).status.shutdown.post()
|
|
|
|
# Force stop
|
|
proxmox.nodes(node).qemu(vmid).status.stop.post()
|
|
```
|
|
|
|
**Delete VM:**
|
|
|
|
```python
|
|
proxmox.nodes(node).qemu(vmid).delete()
|
|
```
|
|
|
|
### Cluster Operations
|
|
|
|
**Get Cluster Status:**
|
|
|
|
```python
|
|
cluster_status = proxmox.cluster.status.get()
|
|
for node in cluster_status:
|
|
if node['type'] == 'node':
|
|
print(f"Node: {node['name']} - {node['online']}")
|
|
```
|
|
|
|
**Get Node Resources:**
|
|
|
|
```python
|
|
node_status = proxmox.nodes(node).status.get()
|
|
print(f"CPU: {node_status['cpu']*100:.1f}%")
|
|
print(f"Memory: {node_status['memory']['used']/1024**3:.1f}GB / {node_status['memory']['total']/1024**3:.1f}GB")
|
|
```
|
|
|
|
### Storage Operations
|
|
|
|
**List Storage:**
|
|
|
|
```python
|
|
for storage in proxmox.storage.get():
|
|
print(f"Storage: {storage['storage']} - Type: {storage['type']} - {storage['active']}")
|
|
```
|
|
|
|
**Get Storage Content:**
|
|
|
|
```python
|
|
storage = "local-lvm"
|
|
content = proxmox.storage(storage).content.get()
|
|
for item in content:
|
|
print(f"{item['volid']} - {item.get('vmid', 'N/A')} - {item['size']/1024**3:.1f}GB")
|
|
```
|
|
|
|
## Terraform Provider Patterns
|
|
|
|
### Basic Resource (VM from Clone)
|
|
|
|
```hcl
|
|
resource "proxmox_vm_qemu" "docker_host" {
|
|
name = "docker-01-nexus"
|
|
target_node = "foxtrot"
|
|
vmid = 101
|
|
|
|
clone = "ubuntu-template"
|
|
full_clone = true
|
|
|
|
cores = 4
|
|
memory = 8192
|
|
sockets = 1
|
|
|
|
network {
|
|
bridge = "vmbr0"
|
|
model = "virtio"
|
|
tag = 30 # VLAN 30
|
|
}
|
|
|
|
disk {
|
|
storage = "local-lvm"
|
|
type = "scsi"
|
|
size = "50G"
|
|
}
|
|
|
|
ipconfig0 = "ip=192.168.3.100/24,gw=192.168.3.1"
|
|
|
|
sshkeys = file("~/.ssh/id_rsa.pub")
|
|
}
|
|
```
|
|
|
|
### Data Sources
|
|
|
|
```hcl
|
|
# Get template information
|
|
data "proxmox_vm_qemu" "template" {
|
|
name = "ubuntu-template"
|
|
target_node = "foxtrot"
|
|
}
|
|
|
|
# Get storage information
|
|
data "proxmox_storage" "local_lvm" {
|
|
node = "foxtrot"
|
|
storage = "local-lvm"
|
|
}
|
|
```
|
|
|
|
## Ansible Module Patterns
|
|
|
|
### Create VM from Template
|
|
|
|
```yaml
|
|
- name: Clone template to create VM
|
|
community.proxmox.proxmox_kvm:
|
|
api_host: "{{ proxmox_api_host }}"
|
|
api_user: "{{ proxmox_api_user }}"
|
|
api_token_id: "{{ proxmox_token_id }}"
|
|
api_token_secret: "{{ proxmox_token_secret }}"
|
|
node: foxtrot
|
|
vmid: 101
|
|
name: docker-01-nexus
|
|
clone: ubuntu-template
|
|
full: true
|
|
storage: local-lvm
|
|
net:
|
|
net0: 'virtio,bridge=vmbr0,tag=30'
|
|
ipconfig:
|
|
ipconfig0: 'ip=192.168.3.100/24,gw=192.168.3.1'
|
|
cores: 4
|
|
memory: 8192
|
|
agent: 1
|
|
state: present
|
|
```
|
|
|
|
### Start VM
|
|
|
|
```yaml
|
|
- name: Start VM
|
|
community.proxmox.proxmox_kvm:
|
|
api_host: "{{ proxmox_api_host }}"
|
|
api_user: "{{ proxmox_api_user }}"
|
|
api_token_id: "{{ proxmox_token_id }}"
|
|
api_token_secret: "{{ proxmox_token_secret }}"
|
|
node: foxtrot
|
|
vmid: 101
|
|
state: started
|
|
```
|
|
|
|
## Matrix Cluster Specifics
|
|
|
|
### Node IP Addresses
|
|
|
|
```python
|
|
MATRIX_NODES = {
|
|
"foxtrot": "192.168.3.5",
|
|
"golf": "192.168.3.6",
|
|
"hotel": "192.168.3.7"
|
|
}
|
|
```
|
|
|
|
### Storage Pools
|
|
|
|
```python
|
|
STORAGE_POOLS = {
|
|
"local": "dir", # Local directory
|
|
"local-lvm": "lvmthin", # LVM thin on boot disk
|
|
"ceph-pool": "rbd" # CEPH RBD (when configured)
|
|
}
|
|
```
|
|
|
|
### Network Bridges
|
|
|
|
```python
|
|
BRIDGES = {
|
|
"vmbr0": "192.168.3.0/24", # Management + VLAN 9 (Corosync)
|
|
"vmbr1": "192.168.5.0/24", # CEPH Public (MTU 9000)
|
|
"vmbr2": "192.168.7.0/24" # CEPH Private (MTU 9000)
|
|
}
|
|
```
|
|
|
|
## Error Handling
|
|
|
|
### Python Example
|
|
|
|
```python
|
|
from proxmoxer import ProxmoxAPI, ResourceException
|
|
import sys
|
|
|
|
try:
|
|
proxmox = ProxmoxAPI('192.168.3.5', user='root@pam', password='pass', verify_ssl=False)
|
|
vm_config = proxmox.nodes('foxtrot').qemu(101).config.get()
|
|
except ResourceException as e:
|
|
print(f"API Error: {e}", file=sys.stderr)
|
|
sys.exit(1)
|
|
except Exception as e:
|
|
print(f"Unexpected error: {e}", file=sys.stderr)
|
|
sys.exit(1)
|
|
```
|
|
|
|
### Ansible Example
|
|
|
|
```yaml
|
|
- name: Clone VM with error handling
|
|
community.proxmox.proxmox_kvm:
|
|
api_host: "{{ proxmox_api_host }}"
|
|
# ... config ...
|
|
register: clone_result
|
|
failed_when: false
|
|
|
|
- name: Check clone result
|
|
ansible.builtin.fail:
|
|
msg: "Failed to clone VM: {{ clone_result.msg }}"
|
|
when: clone_result.failed
|
|
```
|
|
|
|
## API Endpoints Reference
|
|
|
|
### Common Endpoints
|
|
|
|
```text
|
|
GET /api2/json/nodes # List nodes
|
|
GET /api2/json/nodes/{node}/qemu # List VMs on node
|
|
GET /api2/json/nodes/{node}/qemu/{vmid} # Get VM status
|
|
POST /api2/json/nodes/{node}/qemu/{vmid}/clone # Clone VM
|
|
PUT /api2/json/nodes/{node}/qemu/{vmid}/config # Update config
|
|
POST /api2/json/nodes/{node}/qemu/{vmid}/status/start # Start VM
|
|
POST /api2/json/nodes/{node}/qemu/{vmid}/status/shutdown # Stop VM
|
|
DELETE /api2/json/nodes/{node}/qemu/{vmid} # Delete VM
|
|
|
|
GET /api2/json/cluster/status # Cluster status
|
|
GET /api2/json/storage # List storage
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
1. **Use API tokens** - More secure than password authentication
|
|
2. **Handle SSL properly** - Use `verify_ssl=True` with proper CA cert in production
|
|
3. **Check task completion** - Clone/migrate operations are async, poll for completion
|
|
4. **Error handling** - Always catch ResourceException and provide meaningful errors
|
|
5. **Rate limiting** - Don't hammer the API, add delays in loops
|
|
6. **Idempotency** - Check if resource exists before creating
|
|
7. **Use VMID ranges** - Reserve ranges for different purposes (templates: 9000-9999, VMs: 100-999)
|
|
|
|
## Further Reading
|
|
|
|
- [Proxmox VE API Documentation](https://pve.proxmox.com/pve-docs/api-viewer/)
|
|
- [proxmoxer GitHub](https://github.com/proxmoxer/proxmoxer)
|
|
- [community.proxmox Collection](https://docs.ansible.com/ansible/latest/collections/community/proxmox/)
|