Pyinfra/Deploy automatico VM Proxmox

Da GazziNet.
Vai alla navigazione Vai alla ricerca

Pyinfra/Deploy automatico VM Proxmox

Questa pagina descrive la soluzione concreta pubblicata su bot.gazzi.net/pyinfra/. L'obiettivo non e insegnare pyinfra in astratto, ma permettere a una persona umana di capire come e fatta l'automazione, come si usa e come si mantiene.

Obiettivo

Consentire la creazione guidata di VM Proxmox via browser, con:

  • autenticazione LDAP
  • validazione dei parametri
  • job serializzati
  • log consultabili
  • provisioning reale eseguito via pyinfra

Cosa vede l'utente

La form pubblica consente di inserire:

  • VMID
  • nome VM
  • utente amministrativo iniziale
  • password iniziale
  • CPU
  • RAM
  • disco
  • rete DHCP o statica
  • bridge
  • VLAN
  • gateway
  • CIDR
  • scelta se avviare subito la VM

Pulsanti di supporto:

  • ricerca del primo VMID libero a partire da 100
  • elenco bridge disponibili
  • elenco VLAN disponibili sul bridge scelto

Flusso umano

Una persona normale puo leggere il sistema cosi:

  1. apre la pagina
  2. fa login LDAP
  3. compila i parametri
  4. verifica rete e VMID
  5. preme Crea VM
  6. vede partire il job
  7. osserva il log recenti nella stessa pagina

Flusso tecnico

  1. Nginx pubblica /pyinfra/
  2. Flask gestisce login, pagina, API e job
  3. il job lancia pyinfra @local
  4. il deploy pyinfra richiama un helper Python
  5. l'helper apre una sessione SSH verso Proxmox
  6. Proxmox crea la VM e la configura con cloud-init
  7. se la VM parte subito, il sistema aspetta il primo boot e pulisce lo snippet cloud-init

Componenti

1. Frontend Flask

Serve HTML direttamente dall'app e contiene:

  • form
  • validazioni lato browser
  • chiamate AJAX alle API interne
  • lista job recenti

2. Login LDAP

L'utente non entra direttamente se non ha credenziali LDAP valide.

3. API interne

Le API servono per:

  • health check
  • elenco job
  • lookup bridge
  • lookup VLAN
  • validazione bridge + VLAN
  • ricerca VMID libero
  • creazione job

4. Runner pyinfra

Pyinfra viene eseguito in locale con inventario implicito @local.

5. Helper Proxmox

L'helper Python usa paramiko e comandi qm per creare la VM.

File importanti

Versionati:

  • scripts-repo/pyinfra-proxmox-webui/app.py
  • scripts-repo/pyinfra-proxmox-webui/deploys/create_vm.py
  • scripts-repo/pyinfra-proxmox-webui/lib/proxmox_ssh.py
  • scripts-repo/pyinfra-proxmox-webui/systemd/pyinfra-webui.service
  • scripts-repo/pyinfra-proxmox-webui/proxy01-bot-pyinfra-location.conf.example
  • scripts-repo/pyinfra-proxmox-webui/.env.example

Runtime:

  • /opt/pyinfra-webui
  • /etc/pyinfra-webui/pyinfra-webui.env
  • /etc/systemd/system/pyinfra-webui.service
  • /var/lib/pyinfra-webui

Esempio ragionato di environment file

Usare placeholder, non segreti reali:

APP_HOST=0.0.0.0
APP_PORT=18180
APP_BASE_PATH=/pyinfra
APP_TOKEN=CHANGEME
APP_SECRET_KEY=CHANGEME
APP_STATE_DIR=/var/lib/pyinfra-webui

PROXMOX_SSH_HOST=PROXMOX_HOST
PROXMOX_SSH_PORT=22
PROXMOX_SSH_USER=root
PROXMOX_SSH_PASS=CHANGEME

PROXMOX_IMAGE=/var/lib/vz/template/iso/noble-server-cloudimg-amd64.img
PROXMOX_STORAGE=local
PROXMOX_CLOUDINIT_STORAGE=local
PROXMOX_BRIDGE=vmbr1
PROXMOX_GATEWAY=172.16.1.1
PROXMOX_CPU_TYPE=x86-64-v2-AES
PROXMOX_CIUSER=ubuntu
PROXMOX_CIPASSWORD=CHANGEME
PROXMOX_CICUSTOM_USER=local:snippets/gazzi-ubuntu-user.yaml

LDAP_URI=ldap://LDAP_HOST:389
LDAP_USER_DN_TEMPLATE=uid={username},ou=People,dc=gazzi,dc=local

Cosa significano le variabili

  • APP_HOST e APP_PORT: bind locale del servizio Flask
  • APP_BASE_PATH: prefisso usato quando l'app sta dietro reverse proxy su /pyinfra
  • APP_TOKEN: token opzionale per protezione addizionale API
  • APP_SECRET_KEY: chiave sessione Flask
  • APP_STATE_DIR: directory per log e stato job
  • PROXMOX_*: connessione e default di provisioning
  • LDAP_*: endpoint e template DN per login utente

Reverse proxy

Snippet di riferimento:

location = /pyinfra {
    return 301 /pyinfra/;
}

location /pyinfra/ {
    proxy_pass http://BOT_GAZZI_LOCAL:18180/;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Port $server_port;
    proxy_set_header X-Forwarded-Prefix /pyinfra;
    proxy_redirect off;
}

Service

[Unit]
Description=Pyinfra Proxmox Web UI
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=pyinfraweb
Group=pyinfraweb
WorkingDirectory=/opt/pyinfra-webui
EnvironmentFile=/etc/pyinfra-webui/pyinfra-webui.env
ExecStart=/opt/pyinfra-webui/venv/bin/python /opt/pyinfra-webui/app.py
Restart=on-failure
RestartSec=3

[Install]
WantedBy=multi-user.target

Deploy iniziale

sudo mkdir -p /opt/pyinfra-webui /etc/pyinfra-webui /var/lib/pyinfra-webui
sudo chown -R pyinfraweb:pyinfraweb /opt/pyinfra-webui /var/lib/pyinfra-webui

cd /opt/pyinfra-webui
python3 -m venv venv
./venv/bin/pip install -U pip
./venv/bin/pip install -r requirements.txt

sudo install -m 0644 systemd/pyinfra-webui.service /etc/systemd/system/pyinfra-webui.service
sudo systemctl daemon-reload
sudo systemctl enable --now pyinfra-webui.service

Aggiornamento

cd /opt/pyinfra-webui
./venv/bin/pip install -r requirements.txt
sudo systemctl restart pyinfra-webui.service

Verifiche rapide

Applicative:

curl -I https://bot.gazzi.net/pyinfra/
curl -sS http://127.0.0.1:18180/api/health

Service:

systemctl status pyinfra-webui.service
journalctl -u pyinfra-webui.service -n 100 --no-pager

Funzionali:

  • test login LDAP
  • test bridge disponibili
  • test VLAN disponibili
  • test validazione bridge + VLAN
  • test ricerca VMID libero
  • test provisioning di una VM reale o di test

Esempio di percorso reale

Caso semplice:

  • rete in DHCP
  • bridge scelto manualmente
  • nessuna VLAN
  • VM avviata subito

Caso avanzato:

  • rete statica
  • bridge scelto da lookup
  • VLAN scelta da lookup
  • VMID trovato automaticamente
  • utente iniziale definito dall'operatore

Sicurezza

Punti importanti:

  • non mettere segreti in wiki o Git
  • usare sempre HTTPS sul path pubblico
  • il job parte solo a richiesta dell'utente autenticato
  • la UI accetta un solo job alla volta per ridurre collisioni banali
  • lo snippet cloud-init viene rimosso dopo il primo boot solo se la VM parte subito

Limiti noti

  • se start_after_create=false, lo snippet cloud-init resta finche la VM non completa il primo avvio
  • la validazione VLAN dipende da cio che Proxmox espone in quel momento
  • la pagina non sostituisce un orchestratore completo multi-tenant: e un ingresso operativo controllato

Dove leggere il codice

Per la spiegazione dettagliata:

Per gli esempi generali: