API ile Proxmox Otomasyonu: Örnek Kullanım Senaryoları

Proxmox’u web arayüzünden yönetmek başlangıç için yeterli olabilir, ama onlarca VM ve konteyner yönetir hale geldiğinizde tıkladığınız her buton size zaman kaybettirmeye başlar. İşte tam bu noktada Proxmox’un sunduğu RESTful API devreye giriyor. Altyapınızı kodla yönetmek, tekrar eden görevleri otomatize etmek ve kendi özel araçlarınızı geliştirmek için ihtiyacınız olan her şey bu API’da mevcut.

Bu yazıda sıfırdan başlayıp gerçek dünya senaryolarına kadar uzanan pratik Proxmox API kullanımını ele alacağız. Bash scriptlerinden Python’a, basit sorgulardan karmaşık otomasyona kadar her şeyi göreceksiniz.

Proxmox API’ye Giriş ve Kimlik Doğrulama

Proxmox API’si varsayılan olarak https://PROXMOX_IP:8006/api2/json adresinde çalışır. Her istek için kimlik doğrulaması gereklidir ve bunun iki yolu vardır.

Ticket tabanlı kimlik doğrulama geçici bir oturum tokeni üretir. Her 2 saatte bir yenilenmesi gerekir ancak hızlı scriptler için uygundur.

API Token kullanımı ise üretim ortamları için önerilen yöntemdir. Kullanıcıya bağlı uzun ömürlü tokenlar oluşturabilir, yetki kısıtlaması yapabilirsiniz.

Önce ticket tabanlı kimlik doğrulama ile başlayalım:

#!/bin/bash
PROXMOX_HOST="192.168.1.10"
PROXMOX_PORT="8006"
USERNAME="root@pam"
PASSWORD="sifreniz"

# Ticket al
RESPONSE=$(curl -s -k -X POST 
  "https://${PROXMOX_HOST}:${PROXMOX_PORT}/api2/json/access/ticket" 
  -d "username=${USERNAME}&password=${PASSWORD}")

# Token ve CSRF değerlerini çıkar
TICKET=$(echo $RESPONSE | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['data']['ticket'])")
CSRF=$(echo $RESPONSE | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['data']['CSRFPreventionToken'])")

echo "Ticket: $TICKET"
echo "CSRF: $CSRF"

# Bu değerleri sonraki isteklerde kullan
curl -s -k 
  -H "Cookie: PVEAuthCookie=${TICKET}" 
  -H "CSRFPreventionToken: ${CSRF}" 
  "https://${PROXMOX_HOST}:${PROXMOX_PORT}/api2/json/nodes"

API Token ile çalışmak daha temizdir. Önce Proxmox arayüzünden veya CLI’dan token oluşturun:

# Proxmox sunucusunda çalıştırın
pveum user token add root@pam otomasyon-token --privsep=0

# Çıktıda token değeri görünecek, bunu kaydedin
# Örnek: root@pam!otomasyon-token=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Token ile istek atmak çok daha basittir:

#!/bin/bash
PROXMOX_HOST="192.168.1.10"
API_TOKEN="root@pam!otomasyon-token=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

curl -s -k 
  -H "Authorization: PVEAPIToken=${API_TOKEN}" 
  "https://${PROXMOX_HOST}:8006/api2/json/nodes" | python3 -m json.tool

Senaryo 1: Tüm Cluster Durumunu İzleme

Sabah işe geldiğinizde cluster’ın genel sağlığını hızlıca görmek istiyorsunuz. Bunun için tüm node’ları, üzerindeki VM’leri ve kaynak kullanımını tek seferde çeken bir script yazalım:

#!/bin/bash

PROXMOX_HOST="192.168.1.10"
API_TOKEN="root@pam!monitor-token=TOKEN_DEGERINIZ"
BASE_URL="https://${PROXMOX_HOST}:8006/api2/json"

api_get() {
  curl -s -k 
    -H "Authorization: PVEAPIToken=${API_TOKEN}" 
    "${BASE_URL}/$1"
}

echo "=== PROXMOX CLUSTER DURUM RAPORU ==="
echo "Tarih: $(date)"
echo ""

# Tüm node'ları listele
NODES=$(api_get "nodes" | python3 -c "
import sys, json
data = json.load(sys.stdin)['data']
for node in data:
    cpu_pct = round(node['cpu'] * 100, 2)
    mem_used = round(node['mem'] / 1024 / 1024 / 1024, 2)
    mem_total = round(node['maxmem'] / 1024 / 1024 / 1024, 2)
    status = node['status']
    print(f"Node: {node['node']} | Durum: {status} | CPU: {cpu_pct}% | RAM: {mem_used}/{mem_total} GB")
")

echo "$NODES"
echo ""

# Her node'daki VM sayısını al
for node in $(api_get "nodes" | python3 -c "import sys,json; [print(n['node']) for n in json.load(sys.stdin)['data']]"); do
  VM_COUNT=$(api_get "nodes/${node}/qemu" | python3 -c "import sys,json; d=json.load(sys.stdin)['data']; print(len(d))")
  CT_COUNT=$(api_get "nodes/${node}/lxc" | python3 -c "import sys,json; d=json.load(sys.stdin)['data']; print(len(d))")
  echo "  $node: $VM_COUNT VM, $CT_COUNT Konteyner"
done

Bu scripti cron’a ekleyip her sabah mail atmasını sağlayabilirsiniz:

# crontab -e
0 8 * * 1-5 /opt/scripts/cluster-rapor.sh | mail -s "Proxmox Sabah Raporu" [email protected]

Senaryo 2: Toplu VM Snapshot Alma

Güncelleme gecesi geldi ve 20 VM’in snapshot’ını tek tek almak istemiyorsunuz. Bu script tüm çalışan VM’lerin snapshot’ını alır ve işlem takibini yapar:

#!/bin/bash

PROXMOX_HOST="192.168.1.10"
API_TOKEN="root@pam!backup-token=TOKEN_DEGERINIZ"
BASE_URL="https://${PROXMOX_HOST}:8006/api2/json"
SNAPSHOT_NAME="guncelleme-oncesi-$(date +%Y%m%d)"
NODE="pve01"

echo "Snapshot alınıyor: ${SNAPSHOT_NAME}"
echo "----------------------------------------"

# Çalışan tüm VM'leri al
VMIDS=$(curl -s -k 
  -H "Authorization: PVEAPIToken=${API_TOKEN}" 
  "${BASE_URL}/nodes/${NODE}/qemu" | 
  python3 -c "
import sys, json
vms = json.load(sys.stdin)['data']
for vm in vms:
    if vm['status'] == 'running':
        print(vm['vmid'])
")

BASARILI=0
BASARISIZ=0

for VMID in $VMIDS; do
  echo -n "VM ${VMID} snapshot alınıyor... "

  TASK=$(curl -s -k -X POST 
    -H "Authorization: PVEAPIToken=${API_TOKEN}" 
    "${BASE_URL}/nodes/${NODE}/qemu/${VMID}/snapshot" 
    -d "snapname=${SNAPSHOT_NAME}&description=Otomatik snapshot - guncelleme oncesi")

  TASKID=$(echo $TASK | python3 -c "import sys,json; print(json.load(sys.stdin)['data'])" 2>/dev/null)

  if [ -n "$TASKID" ]; then
    # Task tamamlanana kadar bekle
    for i in $(seq 1 30); do
      sleep 2
      STATUS=$(curl -s -k 
        -H "Authorization: PVEAPIToken=${API_TOKEN}" 
        "${BASE_URL}/nodes/${NODE}/tasks/${TASKID}/status" | 
        python3 -c "import sys,json; print(json.load(sys.stdin)['data']['status'])")

      if [ "$STATUS" = "stopped" ]; then
        echo "TAMAM"
        BASARILI=$((BASARILI + 1))
        break
      fi
    done
  else
    echo "HATA"
    BASARISIZ=$((BASARISIZ + 1))
  fi
done

echo "----------------------------------------"
echo "Sonuc: $BASARILI basarili, $BASARISIZ basarisiz"

Senaryo 3: Python ile VM Provisioning Otomasyonu

Bash scriptleri basit işler için yeterli ama daha karmaşık senaryolarda Python çok daha güçlüdür. proxmoxer kütüphanesi ile şablon klonlama ve konfigürasyon işlemlerini otomatikleştiren bir script yazalım:

pip3 install proxmoxer requests
#!/usr/bin/env python3
"""
Proxmox VM Provisioning Scripti
Kullanim: python3 provision.py --name web-server-01 --cores 4 --memory 8192
"""

import argparse
import time
from proxmoxer import ProxmoxAPI

# Konfigürasyon
PROXMOX_HOST = "192.168.1.10"
API_TOKEN_ID = "root@pam!provision-token"
API_TOKEN_SECRET = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
NODE = "pve01"
TEMPLATE_VMID = 9000  # Ubuntu 22.04 template VM ID
STORAGE = "local-lvm"
NETWORK_BRIDGE = "vmbr0"

def create_vm(name, cores, memory, disk_size, start_after=True):
    """
    Şablondan yeni VM oluştur ve yapılandır
    """
    prox = ProxmoxAPI(
        PROXMOX_HOST,
        user=API_TOKEN_ID,
        token_value=API_TOKEN_SECRET,
        verify_ssl=False
    )

    # Boş bir VMID bul
    vmid = prox.cluster.nextid.get()
    print(f"Yeni VM ID: {vmid}")

    # Şablonu klonla
    print(f"Şablon {TEMPLATE_VMID} klonlanıyor -> {name} ({vmid})")
    task = prox.nodes(NODE).qemu(TEMPLATE_VMID).clone.post(
        newid=vmid,
        name=name,
        full=1,
        storage=STORAGE
    )

    # Klonlama tamamlanana kadar bekle
    wait_for_task(prox, NODE, task)
    print("Klonlama tamamlandi.")

    # VM konfigürasyonunu güncelle
    print(f"Konfigürasyon guncelleniyor: {cores} core, {memory}MB RAM")
    prox.nodes(NODE).qemu(vmid).config.put(
        cores=cores,
        memory=memory,
        net0=f"virtio,bridge={NETWORK_BRIDGE}",
        ipconfig0=f"ip=dhcp",
        ciuser="sysadmin",
        cipassword="GucluSifre123!",
        sshkeys="ssh-rsa AAAAB3... [email protected]"
    )

    # Disk boyutunu ayarla
    if disk_size:
        print(f"Disk boyutu ayarlaniyor: +{disk_size}G")
        prox.nodes(NODE).qemu(vmid).resize.put(
            disk="scsi0",
            size=f"+{disk_size}G"
        )

    # VM'i başlat
    if start_after:
        print("VM baslatiliyor...")
        prox.nodes(NODE).qemu(vmid).status.start.post()
        print(f"VM {name} ({vmid}) baslatildi!")

    return vmid

def wait_for_task(prox, node, task_id, timeout=300):
    """Task tamamlanana kadar bekle"""
    elapsed = 0
    while elapsed < timeout:
        status = prox.nodes(node).tasks(task_id).status.get()
        if status['status'] == 'stopped':
            if status.get('exitstatus') == 'OK':
                return True
            else:
                raise Exception(f"Task basarisiz: {status.get('exitstatus')}")
        time.sleep(3)
        elapsed += 3
        print(".", end="", flush=True)
    raise TimeoutError("Task zaman asimina ugradi")

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Proxmox VM Provisioning")
    parser.add_argument("--name", required=True, help="VM adi")
    parser.add_argument("--cores", type=int, default=2, help="CPU core sayisi")
    parser.add_argument("--memory", type=int, default=4096, help="RAM (MB)")
    parser.add_argument("--disk", type=int, default=20, help="Ekstra disk (GB)")
    parser.add_argument("--no-start", action="store_true", help="Olusturunca baslatma")

    args = parser.parse_args()

    vmid = create_vm(
        name=args.name,
        cores=args.cores,
        memory=args.memory,
        disk_size=args.disk,
        start_after=not args.no_start
    )
    print(f"nVM basariyla olusturuldu! VMID: {vmid}")

Bu scripti kullanmak son derece basit:

# Yeni web sunucusu oluştur
python3 provision.py --name web-server-01 --cores 4 --memory 8192 --disk 50

# DB sunucusu oluştur, henüz başlatma
python3 provision.py --name db-master-01 --cores 8 --memory 16384 --disk 100 --no-start

Senaryo 4: Kaynak Kullanım Alarmı

Disk dolmadan, RAM bitmeden haberdar olmak istiyorsunuz. Bu script her 5 dakikada çalışıp eşiği aşan VM’leri Slack veya mail ile bildirir:

#!/bin/bash

PROXMOX_HOST="192.168.1.10"
API_TOKEN="root@pam!monitor-token=TOKEN"
BASE_URL="https://${PROXMOX_HOST}:8006/api2/json"
SLACK_WEBHOOK="https://hooks.slack.com/services/XXXXX/YYYYY/ZZZZZ"
CPU_ESIK=85
RAM_ESIK=90

send_alert() {
  local message="$1"
  echo "[ALARM] $message"

  # Slack bildirimi
  curl -s -X POST "$SLACK_WEBHOOK" 
    -H "Content-Type: application/json" 
    -d "{"text":":warning: *Proxmox Alarm*n${message}"}" > /dev/null
}

for NODE in $(curl -s -k 
  -H "Authorization: PVEAPIToken=${API_TOKEN}" 
  "${BASE_URL}/nodes" | python3 -c "import sys,json; [print(n['node']) for n in json.load(sys.stdin)['data']]"); do

  # Çalışan VM'lerin kaynak kullanımını kontrol et
  curl -s -k 
    -H "Authorization: PVEAPIToken=${API_TOKEN}" 
    "${BASE_URL}/nodes/${NODE}/qemu" | 
  python3 -c "
import sys, json
data = json.load(sys.stdin)['data']
for vm in data:
    if vm['status'] != 'running':
        continue
    cpu_pct = round(vm.get('cpu', 0) * 100, 1)
    mem_pct = round(vm.get('mem', 0) / max(vm.get('maxmem', 1), 1) * 100, 1)
    vmid = vm['vmid']
    name = vm.get('name', 'unknown')

    if cpu_pct > ${CPU_ESIK}:
        print(f'CPU|{name} ({vmid}) CPU kullanimi yuksek: {cpu_pct}%')
    if mem_pct > ${RAM_ESIK}:
        print(f'RAM|{name} ({vmid}) RAM kullanimi yuksek: {mem_pct}%')
" | while IFS='|' read -r tip mesaj; do
    send_alert "$mesaj"
  done

done

Senaryo 5: LXC Konteyner Fabrikası

Geliştirici ekibiniz her sprint başında test ortamı istiyor. Bu script istek üzerine LXC konteynerleri oluşturur, yapılandırır ve SSH erişimini hazırlar:

#!/bin/bash

PROXMOX_HOST="192.168.1.10"
API_TOKEN="root@pam!dev-token=TOKEN"
BASE_URL="https://${PROXMOX_HOST}:8006/api2/json"
NODE="pve01"
STORAGE="local-lvm"
TEMPLATE="local:vztmpl/ubuntu-22.04-standard_22.04-1_amd64.tar.zst"

create_lxc() {
  local DEV_ADI="$1"
  local PROJE="$2"

  # Sonraki boş ID al
  CTID=$(curl -s -k 
    -H "Authorization: PVEAPIToken=${API_TOKEN}" 
    "${BASE_URL}/cluster/nextid" | python3 -c "import sys,json; print(json.load(sys.stdin)['data'])")

  echo "Konteyner olusturuluyor: ${PROJE}-${DEV_ADI} (CT ID: ${CTID})"

  # LXC oluştur
  TASK=$(curl -s -k -X POST 
    -H "Authorization: PVEAPIToken=${API_TOKEN}" 
    "${BASE_URL}/nodes/${NODE}/lxc" 
    -d "vmid=${CTID}" 
    -d "hostname=${PROJE}-${DEV_ADI}" 
    -d "ostemplate=${TEMPLATE}" 
    -d "storage=${STORAGE}" 
    -d "rootfs=${STORAGE}:10" 
    -d "cores=2" 
    -d "memory=2048" 
    -d "swap=512" 
    -d "net0=name=eth0,bridge=vmbr0,ip=dhcp" 
    -d "password=DevPass123!" 
    -d "ssh-public-keys=ssh-rsa AAAA... [email protected]" 
    -d "unprivileged=1" 
    -d "start=1" | python3 -c "import sys,json; print(json.load(sys.stdin)['data'])")

  echo "Task ID: $TASK - Tamamlanmasi bekleniyor..."

  # Tamamlanmasını bekle
  for i in $(seq 1 20); do
    sleep 3
    STATUS=$(curl -s -k 
      -H "Authorization: PVEAPIToken=${API_TOKEN}" 
      "${BASE_URL}/nodes/${NODE}/tasks/${TASK}/status" | 
      python3 -c "import sys,json; print(json.load(sys.stdin)['data']['status'])")

    if [ "$STATUS" = "stopped" ]; then
      echo "Konteyner hazir! CT ID: ${CTID}"
      echo "SSH: ssh root@$(get_ct_ip $CTID)"
      break
    fi
    echo -n "."
  done
}

# Kullanim
# ./lxc-fabrika.sh ahmet-yilmaz backend-api
create_lxc "$1" "$2"

Senaryo 6: Otomatik Yedek Dogrulama

Yedek aldınız ama çalışıyor mu? Bu script son yedekleri listeler ve boyut/tarih kontrolü yaparak sonuçları raporlar:

#!/usr/bin/env python3

from proxmoxer import ProxmoxAPI
from datetime import datetime, timedelta
import sys

prox = ProxmoxAPI(
    "192.168.1.10",
    user="root@pam!backup-token",
    token_value="TOKEN_DEGERINIZ",
    verify_ssl=False
)

STORAGE = "backup-storage"
MAX_YEDEK_YASI_SAAT = 26  # 26 saatten eski yedek varsa uyar

print("=== YEDEK DOGRULAMA RAPORU ===")
print(f"Tarih: {datetime.now().strftime('%Y-%m-%d %H:%M')}")
print("")

uyarilar = []

for node in prox.nodes.get():
    node_name = node['node']

    try:
        yedekler = prox.nodes(node_name).storage(STORAGE).content.get(
            content="backup"
        )
    except Exception as e:
        print(f"[HATA] {node_name} yedekleri okunamadi: {e}")
        continue

    # VM bazinda son yedekleri grupla
    vm_yedekleri = {}
    for yedek in yedekler:
        vmid = yedek.get('vmid', 'unknown')
        ctime = yedek.get('ctime', 0)
        if vmid not in vm_yedekleri or ctime > vm_yedekleri[vmid]['ctime']:
            vm_yedekleri[vmid] = yedek

    print(f"Node: {node_name} ({len(vm_yedekleri)} VM yedegi)")

    for vmid, yedek in sorted(vm_yedekleri.items()):
        yedek_tarihi = datetime.fromtimestamp(yedek['ctime'])
        yas_saat = (datetime.now() - yedek_tarihi).total_seconds() / 3600
        boyut_gb = round(yedek['size'] / 1024 / 1024 / 1024, 2)

        durum = "OK" if yas_saat <= MAX_YEDEK_YASI_SAAT else "UYARI"

        print(f"  VM {vmid}: {boyut_gb} GB | {yedek_tarihi.strftime('%Y-%m-%d %H:%M')} | {durum}")

        if durum == "UYARI":
            uyarilar.append(f"VM {vmid} yedegi eski: {round(yas_saat, 1)} saat once alinmis")

print("")
if uyarilar:
    print("=== UYARILAR ===")
    for u in uyarilar:
        print(f"[!] {u}")
    sys.exit(1)
else:
    print("Tum yedekler guncel. Sorun yok.")
    sys.exit(0)

API Kullanımında Dikkat Edilmesi Gerekenler

Proxmox API ile çalışırken karşılaşabileceğiniz birkaç önemli nokta var:

Rate Limiting: Proxmox API’si çok hızlı istek atılırsa bağlantıları reddedebilir. Döngü içindeki istekler arasına kısa bir sleep ekleyin.

SSL Sertifikası: Test ortamlarında self-signed sertifika kullanılıyorsa -k flag’i veya Python’da verify_ssl=False kullanın. Üretimde kesinlikle geçerli sertifika kullanın.

Token Yetkileri: Her token için en az yetkiyi tanımlayın. Monitoring tokeni sadece VM.Monitor ve Datastore.Audit yetkisine sahip olmalı, provisioning tokeni ise VM.Allocate ve VM.Clone yetkilerine ihtiyaç duyar.

Task Takibi: API’deki uzun süren işlemler (klonlama, backup gibi) asenkron çalışır ve bir task ID döner. İşlemin tamamlandığını anlamak için task durumunu sorgulamak zorundasınız, aksi halde yarım kalmış işlemlerle uğraşırsınız.

Hata Yönetimi: API 4xx veya 5xx dönüyorsa detaylı hata mesajını parse etmeyi ihmal etmeyin. Proxmox genellikle çok açıklayıcı hata mesajları döner.

Loglama: Otomasyon scriptlerinizin ne yaptığını mutlaka loglayın. Bir şeyler ters gittiğinde kim ne zaman hangi VM’i sildi diye bakabiliyor olmanız hayat kurtarır.

Sonuç

Proxmox API’si, altyapı yönetimini gerçek anlamda “infrastructure as code” seviyesine taşımanızı sağlar. Sabahları cluster durumunu kontrol etmekten yeni geliştirici ortamı hazırlamaya, yedek doğrulamadan toplu snapshot almaya kadar pek çok tekrar eden görevi devre dışı bırakabilirsiniz.

Başlamak için karmaşık bir proje kurmanıza gerek yok. Önce mevcut süreçlerinizde en çok zaman harcadığınız tekrar eden görevi belirleyin ve o iş için küçük bir script yazın. İlk birkaç başarılı otomasyon, sizi daha büyük şeyler yazmaya teşvik edecektir.

Üretim ortamında token tabanlı kimlik doğrulamayı, minimum yetki prensibini ve kapsamlı loglamayı asla atlamamalısınız. API güçlü bir araçtır ve yanlış kullanıldığında VM silmek de dahil olmak üzere geri alınamaz işlemler yapabilir. Scriptlerinizi önce test ortamında deneyin, kademeli olarak üretime taşıyın.

Yorum yapın