Pyinfra/Deploy automatico VM Proxmox

Da GazziNet.
Versione del 29 mar 2026 alle 18:51 di Maintenance script (discussione | contributi) (Aggiunta runbook operativo deploy automatico VM Proxmox)
(diff) ← Versione meno recente | Versione attuale (diff) | Versione più recente → (diff)
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:

<syntaxhighlight lang="ini"> 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 </syntaxhighlight>

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: <syntaxhighlight lang="nginx"> 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;

} </syntaxhighlight>

Service

<syntaxhighlight lang="ini"> [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 </syntaxhighlight>

Deploy iniziale

<syntaxhighlight lang="bash"> 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 </syntaxhighlight>

Aggiornamento

<syntaxhighlight lang="bash"> cd /opt/pyinfra-webui ./venv/bin/pip install -r requirements.txt sudo systemctl restart pyinfra-webui.service </syntaxhighlight>

Verifiche rapide

Applicative: <syntaxhighlight lang="bash"> curl -I https://bot.gazzi.net/pyinfra/ curl -sS http://127.0.0.1:18180/api/health </syntaxhighlight>

Service: <syntaxhighlight lang="bash"> systemctl status pyinfra-webui.service journalctl -u pyinfra-webui.service -n 100 --no-pager </syntaxhighlight>

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: