Pyinfra: differenze tra le versioni

Da GazziNet.
Vai alla navigazione Vai alla ricerca
(Creazione pagina introduttiva su pyinfra con esempi e link ufficiali)
 
(Aggiornamento)
Riga 1: Riga 1:
__NOTOC__
= Pyinfra =
= Pyinfra =


'''Pyinfra''' e uno strumento open source di automazione e deploy infrastrutturale scritto in Python. Può essere usato sia per comandi ad-hoc sia per deploy ripetibili definiti in file Python versionabili in Git.
'''Pyinfra''' in GazziNet non e solo una pagina teorica: al 2026-03-29 e stato usato per pubblicare una web UI operativa che consente di creare VM Proxmox via browser, con autenticazione LDAP e job eseguiti on demand.


== Concetto base ==
Questa pagina raccoglie il runbook sintetico della soluzione realmente messa in esercizio, con focus su deploy, configurazione, uso e verifiche. I dettagli sensibili restano fuori dalla wiki e vanno tenuti nei file runtime dedicati.
Pyinfra lavora con due elementi principali:
* '''Inventory''': host, gruppi e dati associati agli host.
* '''Operations''': stato desiderato o comandi da applicare ai target.


L'approccio e vicino ad Ansible sul piano operativo, ma invece di descrivere i deploy soprattutto in YAML, pyinfra usa Python.
== Cosa e stato realizzato ==
* UI pubblica su <code>https://bot.gazzi.net/pyinfra/</code>
* autenticazione LDAP prima dell'accesso alla form
* runner <code>pyinfra</code> locale su <code>bot.gazzi.local</code>
* provisioning VM su Proxmox via SSH e comandi <code>qm</code>
* scelta di CPU, RAM, disco, bridge, VLAN, DHCP o IP statico
* scelta di utente e password iniziali della VM
* pulsante per trovare il primo VMID libero a partire da <code>100</code>
* lookup bridge e VLAN direttamente dal nodo Proxmox
* validazione preventiva della coppia <code>bridge + vlan</code>
* cleanup dello snippet cloud-init dopo il primo boot se la VM parte subito


== Come funziona ==
== Architettura logica ==
Secondo la documentazione ufficiale, l'esecuzione avviene in cinque fasi:
Flusso sintetico:
# lettura di inventory e data
# utente apre <code>bot.gazzi.net/pyinfra/</code>
# connessione ai target
# Nginx su <code>proxy01</code> inoltra verso il servizio su <code>bot.gazzi.local</code>
# preparazione con rilevamento cambiamenti e ordine operazioni
# l'app Flask autentica l'utente via LDAP
# esecuzione delle modifiche
# la UI crea un job locale <code>pyinfra</code>
# disconnessione e cleanup
# il job usa SSH verso Proxmox ed esegue <code>qm create</code> / <code>qm set</code>
# se richiesto, la VM parte subito e viene atteso il completamento di <code>cloud-init</code>


Un punto importante e che pyinfra prepara prima l'ordine delle operazioni e poi le esegue. Questo permette di mantenere l'ordine logico delle operazioni, eseguendo ogni singola operation in parallelo sui target rilevanti.
== Parametri gestiti dalla UI ==
* VMID
* nome VM
* utente amministrativo iniziale
* password iniziale
* CPU
* RAM
* disco
* rete: DHCP o IP statico
* bridge Proxmox
* VLAN Proxmox
* gateway
* CIDR
* avvio automatico della VM a fine creazione


== Inventory ==
Nota pratica:
Un inventory pyinfra contiene:
* se e selezionato '''DHCP''', i campi IP statici vengono disabilitati
* host
* se si usa rete '''statica''', IP, gateway e CIDR diventano obbligatori
* gruppi
* dati di gruppo
* dati per singolo host


Esempio minimale:
== File principali ==
<pre>
Sorgenti versionati:
web_servers = [
* <code>scripts-repo/pyinfra-proxmox-webui/app.py</code>
    "web-01.example.net",
* <code>scripts-repo/pyinfra-proxmox-webui/lib/proxmox_ssh.py</code>
    "web-02.example.net",
* <code>scripts-repo/pyinfra-proxmox-webui/deploys/create_vm.py</code>
]
* <code>scripts-repo/pyinfra-proxmox-webui/systemd/pyinfra-webui.service</code>
* <code>scripts-repo/pyinfra-proxmox-webui/proxy01-bot-pyinfra-location.conf.example</code>
* <code>scripts-repo/pyinfra-proxmox-webui/.env.example</code>


db_servers = [
Runtime:
    ("db-01.example.net", {"install_postgres": True}),
* working directory: <code>/opt/pyinfra-webui</code>
]
* environment file: <code>/etc/pyinfra-webui/pyinfra-webui.env</code>
</pre>
* service systemd: <code>/etc/systemd/system/pyinfra-webui.service</code>
* state dir: <code>/var/lib/pyinfra-webui</code>


I dati associati agli host o ai gruppi possono essere usati nel deploy Python tramite `host.data`.
== Esempio environment file ==
Non inserire password o token nella wiki. Usare placeholder e valorizzare i segreti solo nel file runtime.


== Operations ==
<syntaxhighlight lang="ini">
Le operations descrivono cosa deve essere vero sul sistema target. In molti casi non rappresentano un'azione imperativa ma uno '''stato desiderato'''.
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


Esempio:
PROXMOX_SSH_HOST=PROXMOX_HOST
<pre>
PROXMOX_SSH_PORT=22
from pyinfra.operations import apt, files
PROXMOX_SSH_USER=root
PROXMOX_SSH_PASS=CHANGEME


apt.packages(
PROXMOX_IMAGE=/var/lib/vz/template/iso/noble-server-cloudimg-amd64.img
    name="Install vim",
PROXMOX_STORAGE=local
    packages=["vim"],
PROXMOX_CLOUDINIT_STORAGE=local
    update=True,
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


files.file(
LDAP_URI=ldap://LDAP_HOST:389
    name="Ensure log file exists",
LDAP_USER_DN_TEMPLATE=uid={username},ou=People,dc=gazzi,dc=local
    path="/var/log/app.log",
</syntaxhighlight>
    user="app",
    group="app",
    mode="644",
)
</pre>


Se il target e gia nello stato richiesto, pyinfra non applica cambiamenti ulteriori.
== Service systemd ==
<syntaxhighlight lang="ini">
[Unit]
Description=Pyinfra Proxmox Web UI
After=network-online.target
Wants=network-online.target


== Comandi ad-hoc ==
[Service]
Pyinfra puo essere usato anche direttamente da CLI senza creare un deploy completo.
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


Esempi:
[Install]
<pre>
WantedBy=multi-user.target
pyinfra @local exec -- echo "hello world"
</syntaxhighlight>
pyinfra my-server.net exec -- uptime
pyinfra @docker/ubuntu:22.04 exec -- uname -a
</pre>


== Esempio base di deploy ==
== Reverse proxy ==
Inventory:
Snippet Nginx di riferimento:
<pre>
my_hosts = [
    ("ubuntu2204", {
        "ssh_port": 2222,
        "ssh_hostname": "localhost",
        "ssh_user": "vagrant",
        "_sudo": True,
    }),
    "my-server.net",
]
</pre>


Deploy:
<syntaxhighlight lang="nginx">
<pre>
location = /pyinfra {
from pyinfra.operations import apt
    return 301 /pyinfra/;
}


apt.packages(
location /pyinfra/ {
     name="Ensure vim is installed",
    proxy_pass http://BOT_GAZZI_LOCAL:18180/;
     packages=["vim"],
    proxy_http_version 1.1;
     update=True,
    proxy_set_header Host $host;
)
    proxy_set_header X-Real-IP $remote_addr;
</pre>
    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>


Esecuzione:
== Deploy o aggiornamento ==
<pre>
Sequenza minima lato host applicativo:
pyinfra inventory.py deploy.py
</pre>


== Differenze pratiche rispetto ad Ansible ==
<syntaxhighlight lang="bash">
* usa '''Python''' invece di fare affidamento principalmente su YAML
sudo mkdir -p /opt/pyinfra-webui /etc/pyinfra-webui /var/lib/pyinfra-webui
* e comodo per chi vuole logica, condizioni e riuso direttamente nel linguaggio
sudo chown -R pyinfraweb:pyinfraweb /opt/pyinfra-webui /var/lib/pyinfra-webui
* mantiene il modello inventory + operazioni + stato desiderato
* puo essere piu naturale per team che preferiscono automazione programmabile piuttosto che playbook dichiarativi


== Quando ha senso usarlo ==
cd /opt/pyinfra-webui
* homelab e server Linux
python3 -m venv venv
* provisioning e configurazioni ripetibili
./venv/bin/pip install -U pip
* deploy gestiti in Git
./venv/bin/pip install -r requirements.txt
* ambienti dove Python e gia parte del flusso operativo


== Limiti da tenere presenti ==
sudo install -m 0644 systemd/pyinfra-webui.service /etc/systemd/system/pyinfra-webui.service
* richiede maggiore familiarita con Python rispetto a strumenti piu dichiarativi
sudo systemctl daemon-reload
* alcuni team preferiscono YAML per leggibilita immediata lato operations
sudo systemctl enable --now pyinfra-webui.service
* va progettato con attenzione quando la logica dipende da fatti che possono cambiare durante il deploy
</syntaxhighlight>


== Installazione ==
Poi:
Secondo la documentazione ufficiale, il metodo consigliato e:
* copiare o aggiornare i file dell'app dentro <code>/opt/pyinfra-webui</code>
<pre>
* aggiornare <code>/etc/pyinfra-webui/pyinfra-webui.env</code>
uv tool install pyinfra
* riavviare il servizio
pyinfra --version
</pre>


Alternative supportate: `pipx` oppure `pip` in virtual environment.
Comandi utili:
<syntaxhighlight lang="bash">
sudo systemctl restart pyinfra-webui.service
sudo systemctl status pyinfra-webui.service
journalctl -u pyinfra-webui.service -n 100 --no-pager
curl -sS http://127.0.0.1:18180/api/health
</syntaxhighlight>


== Link ufficiali ==
== Comportamento del provisioning ==
* [https://pyinfra.com/ Sito ufficiale]
La UI raccoglie i parametri e avvia un job che:
* [https://docs.pyinfra.com/en/3.x/ Documentazione]
* verifica che il VMID non esista gia
* [https://docs.pyinfra.com/en/3.x/getting-started.html Getting Started]
* crea la VM cloud-init con <code>qm create</code> e <code>qm set</code>
* [https://docs.pyinfra.com/en/3.x/inventory-data.html Inventory & Data]
* configura <code>net0</code> con bridge ed eventuale tag VLAN
* [https://docs.pyinfra.com/en/3.x/using-operations.html Using Operations]
* imposta <code>ipconfig0</code> in DHCP o statico
* [https://docs.pyinfra.com/en/3.x/deploy-process.html How pyinfra Works]
* genera uno snippet cloud-init per creare l'utente richiesto con sudo
* opzionalmente avvia la VM
* se la VM viene avviata subito, aspetta guest agent e <code>cloud-init status --wait</code>
* rimuove lo snippet cloud-init dopo il primo boot
 
== Sicurezza ==
Regole da mantenere:
* non scrivere in wiki password, token, cookie o dump di sessione
* non copiare in Git segreti o backend interni inutili
* tenere i segreti in <code>/etc/pyinfra-webui/pyinfra-webui.env</code>
* usare HTTPS sul reverse proxy pubblico
* mantenere il controllo umano: il job parte solo a richiesta dell'utente autenticato
 
Nota importante:
* se <code>start_after_create=false</code>, lo snippet cloud-init non puo essere rimosso subito e va pulito dopo il primo avvio completato
 
== API utili ==
Endpoint interni esposti dall'app:
* <code>/api/health</code>
* <code>/api/jobs</code>
* <code>/api/jobs/create-vm</code>
* <code>/api/network/bridges</code>
* <code>/api/network/vlans</code>
* <code>/api/network/validate</code>
* <code>/api/proxmox/free-vmid</code>
 
== Verifiche rapide ==
Verifiche applicative:
<syntaxhighlight lang="bash">
curl -I https://bot.gazzi.net/pyinfra/
curl -sS http://127.0.0.1:18180/api/health
</syntaxhighlight>
 
Verifiche systemd:
<syntaxhighlight lang="bash">
systemctl status pyinfra-webui.service
journalctl -u pyinfra-webui.service -n 50 --no-pager
</syntaxhighlight>
 
Verifiche Proxmox lato UI:
* test lookup bridge
* test lookup VLAN
* test validazione <code>bridge + vlan</code>
* test ricerca VMID libero
 
== Problemi noti ==
* il <code>guid</code> di WordPress o altri metadati editoriali non hanno relazione con questa automazione
* il cleanup automatico dello snippet cloud-init dipende dal primo boot e dalla disponibilita del guest agent
* la VLAN viene validata in base a cio che il nodo Proxmox espone al momento del controllo
 
== Riferimenti collegati ==
* [[Tips Automation]]
* [[Esempi Pyinfra]]
* [[Confronto Ansible vs Pyinfra]]
* [[Installazione Pyinfra su Fedora]]
* [https://www.gazzi.net/pyinfra-proxmox-webui/ Scheda pubblica su WordPress]
* [https://www.gazzi.net/2026/03/29/pyinfra-proxmox-webui-proxmox-ldap-bot-gazzi-net/ Articolo di dettaglio]
 
== Repository ==
Sorgente versionata:
* <code>scripts-repo/pyinfra-proxmox-webui/</code>
 
Questa pagina wiki va tenuta come documentazione operativa ad alto livello e runbook sintetico. Segreti e dettagli sensibili restano fuori dalla wiki.

Versione delle 18:43, 29 mar 2026

Pyinfra

Pyinfra in GazziNet non e solo una pagina teorica: al 2026-03-29 e stato usato per pubblicare una web UI operativa che consente di creare VM Proxmox via browser, con autenticazione LDAP e job eseguiti on demand.

Questa pagina raccoglie il runbook sintetico della soluzione realmente messa in esercizio, con focus su deploy, configurazione, uso e verifiche. I dettagli sensibili restano fuori dalla wiki e vanno tenuti nei file runtime dedicati.

Cosa e stato realizzato

  • UI pubblica su https://bot.gazzi.net/pyinfra/
  • autenticazione LDAP prima dell'accesso alla form
  • runner pyinfra locale su bot.gazzi.local
  • provisioning VM su Proxmox via SSH e comandi qm
  • scelta di CPU, RAM, disco, bridge, VLAN, DHCP o IP statico
  • scelta di utente e password iniziali della VM
  • pulsante per trovare il primo VMID libero a partire da 100
  • lookup bridge e VLAN direttamente dal nodo Proxmox
  • validazione preventiva della coppia bridge + vlan
  • cleanup dello snippet cloud-init dopo il primo boot se la VM parte subito

Architettura logica

Flusso sintetico:

  1. utente apre bot.gazzi.net/pyinfra/
  2. Nginx su proxy01 inoltra verso il servizio su bot.gazzi.local
  3. l'app Flask autentica l'utente via LDAP
  4. la UI crea un job locale pyinfra
  5. il job usa SSH verso Proxmox ed esegue qm create / qm set
  6. se richiesto, la VM parte subito e viene atteso il completamento di cloud-init

Parametri gestiti dalla UI

  • VMID
  • nome VM
  • utente amministrativo iniziale
  • password iniziale
  • CPU
  • RAM
  • disco
  • rete: DHCP o IP statico
  • bridge Proxmox
  • VLAN Proxmox
  • gateway
  • CIDR
  • avvio automatico della VM a fine creazione

Nota pratica:

  • se e selezionato DHCP, i campi IP statici vengono disabilitati
  • se si usa rete statica, IP, gateway e CIDR diventano obbligatori

File principali

Sorgenti versionati:

  • scripts-repo/pyinfra-proxmox-webui/app.py
  • scripts-repo/pyinfra-proxmox-webui/lib/proxmox_ssh.py
  • scripts-repo/pyinfra-proxmox-webui/deploys/create_vm.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:

  • working directory: /opt/pyinfra-webui
  • environment file: /etc/pyinfra-webui/pyinfra-webui.env
  • service systemd: /etc/systemd/system/pyinfra-webui.service
  • state dir: /var/lib/pyinfra-webui

Esempio environment file

Non inserire password o token nella wiki. Usare placeholder e valorizzare i segreti solo nel file runtime.

<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>

Service systemd

<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>

Reverse proxy

Snippet Nginx 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>

Deploy o aggiornamento

Sequenza minima lato host applicativo:

<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>

Poi:

  • copiare o aggiornare i file dell'app dentro /opt/pyinfra-webui
  • aggiornare /etc/pyinfra-webui/pyinfra-webui.env
  • riavviare il servizio

Comandi utili: <syntaxhighlight lang="bash"> sudo systemctl restart pyinfra-webui.service sudo systemctl status pyinfra-webui.service journalctl -u pyinfra-webui.service -n 100 --no-pager curl -sS http://127.0.0.1:18180/api/health </syntaxhighlight>

Comportamento del provisioning

La UI raccoglie i parametri e avvia un job che:

  • verifica che il VMID non esista gia
  • crea la VM cloud-init con qm create e qm set
  • configura net0 con bridge ed eventuale tag VLAN
  • imposta ipconfig0 in DHCP o statico
  • genera uno snippet cloud-init per creare l'utente richiesto con sudo
  • opzionalmente avvia la VM
  • se la VM viene avviata subito, aspetta guest agent e cloud-init status --wait
  • rimuove lo snippet cloud-init dopo il primo boot

Sicurezza

Regole da mantenere:

  • non scrivere in wiki password, token, cookie o dump di sessione
  • non copiare in Git segreti o backend interni inutili
  • tenere i segreti in /etc/pyinfra-webui/pyinfra-webui.env
  • usare HTTPS sul reverse proxy pubblico
  • mantenere il controllo umano: il job parte solo a richiesta dell'utente autenticato

Nota importante:

  • se start_after_create=false, lo snippet cloud-init non puo essere rimosso subito e va pulito dopo il primo avvio completato

API utili

Endpoint interni esposti dall'app:

  • /api/health
  • /api/jobs
  • /api/jobs/create-vm
  • /api/network/bridges
  • /api/network/vlans
  • /api/network/validate
  • /api/proxmox/free-vmid

Verifiche rapide

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

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

Verifiche Proxmox lato UI:

  • test lookup bridge
  • test lookup VLAN
  • test validazione bridge + vlan
  • test ricerca VMID libero

Problemi noti

  • il guid di WordPress o altri metadati editoriali non hanno relazione con questa automazione
  • il cleanup automatico dello snippet cloud-init dipende dal primo boot e dalla disponibilita del guest agent
  • la VLAN viene validata in base a cio che il nodo Proxmox espone al momento del controllo

Riferimenti collegati

Repository

Sorgente versionata:

  • scripts-repo/pyinfra-proxmox-webui/

Questa pagina wiki va tenuta come documentazione operativa ad alto livello e runbook sintetico. Segreti e dettagli sensibili restano fuori dalla wiki.