Esempi Pyinfra: differenze tra le versioni
(Espansione esempi Pyinfra con casi base e avanzati) |
(Espansione esempi Pyinfra con casi base e avanzati) |
||
| Riga 14: | Riga 14: | ||
== Esempio base 1: esecuzione su host locali == | == Esempio base 1: esecuzione su host locali == | ||
Se vuoi solo capire la CLI: | Se vuoi solo capire la CLI: | ||
< | <pre> | ||
pyinfra @local exec -- echo "hello world" | pyinfra @local exec -- echo "hello world" | ||
</ | </pre> | ||
Questo serve quando vuoi verificare: | Questo serve quando vuoi verificare: | ||
| Riga 24: | Riga 24: | ||
== Esempio base 2: inventory minimale == | == Esempio base 2: inventory minimale == | ||
< | <pre> | ||
web_servers = [ | web_servers = [ | ||
"web-01.example.net", | "web-01.example.net", | ||
"web-02.example.net", | "web-02.example.net", | ||
] | ] | ||
</ | </pre> | ||
Qui hai solo una lista di host. | Qui hai solo una lista di host. | ||
== Esempio base 3: operation semplice == | == Esempio base 3: operation semplice == | ||
< | <pre> | ||
from pyinfra.operations import server | from pyinfra.operations import server | ||
| Riga 41: | Riga 41: | ||
commands=["uptime"], | commands=["uptime"], | ||
) | ) | ||
</ | </pre> | ||
Esecuzione: | Esecuzione: | ||
< | <pre> | ||
pyinfra inventory.py deploy.py | pyinfra inventory.py deploy.py | ||
</ | </pre> | ||
== Esempio base 4: installare pacchetti == | == Esempio base 4: installare pacchetti == | ||
< | <pre> | ||
from pyinfra.operations import apt | from pyinfra.operations import apt | ||
| Riga 57: | Riga 57: | ||
update=True, | update=True, | ||
) | ) | ||
</ | </pre> | ||
Questo e un esempio di operation idempotente: se i pacchetti sono gia presenti, pyinfra non rifara cambiamenti inutili. | Questo e un esempio di operation idempotente: se i pacchetti sono gia presenti, pyinfra non rifara cambiamenti inutili. | ||
== Esempio base 5: gestire file == | == Esempio base 5: gestire file == | ||
< | <pre> | ||
from pyinfra.operations import files | from pyinfra.operations import files | ||
| Riga 72: | Riga 72: | ||
mode="644", | mode="644", | ||
) | ) | ||
</ | </pre> | ||
== Esempio base 6: gestire servizi == | == Esempio base 6: gestire servizi == | ||
< | <pre> | ||
from pyinfra.operations import systemd | from pyinfra.operations import systemd | ||
| Riga 84: | Riga 84: | ||
enabled=True, | enabled=True, | ||
) | ) | ||
</ | </pre> | ||
== Esempio intermedio 1: dati host == | == Esempio intermedio 1: dati host == | ||
Inventory: | Inventory: | ||
< | <pre> | ||
app_servers = [ | app_servers = [ | ||
("app-01.example.net", {"install_nginx": True}), | ("app-01.example.net", {"install_nginx": True}), | ||
("app-02.example.net", {"install_nginx": False}), | ("app-02.example.net", {"install_nginx": False}), | ||
] | ] | ||
</ | </pre> | ||
Deploy: | Deploy: | ||
< | <pre> | ||
from pyinfra import host | from pyinfra import host | ||
from pyinfra.operations import apt | from pyinfra.operations import apt | ||
| Riga 106: | Riga 106: | ||
update=True, | update=True, | ||
) | ) | ||
</ | </pre> | ||
Qui usi Python per rendere il deploy diverso in base ai dati del target. | Qui usi Python per rendere il deploy diverso in base ai dati del target. | ||
== Esempio intermedio 2: gruppi == | == Esempio intermedio 2: gruppi == | ||
< | <pre> | ||
from pyinfra import host, local | from pyinfra import host, local | ||
from pyinfra.operations import server | from pyinfra.operations import server | ||
| Riga 125: | Riga 125: | ||
commands=["hostname"], | commands=["hostname"], | ||
) | ) | ||
</ | </pre> | ||
Questo pattern e utile quando vuoi dividere la logica in file piu piccoli. | Questo pattern e utile quando vuoi dividere la logica in file piu piccoli. | ||
| Riga 132: | Riga 132: | ||
Questo e il pattern usato nel progetto Proxmox Web UI: pyinfra gira su <code>@local</code> ma esegue un helper esterno che contiene la logica vera. | Questo e il pattern usato nel progetto Proxmox Web UI: pyinfra gira su <code>@local</code> ma esegue un helper esterno che contiene la logica vera. | ||
< | <pre> | ||
#!/usr/bin/env python3 | #!/usr/bin/env python3 | ||
import os | import os | ||
| Riga 149: | Riga 149: | ||
commands=[cmd], | commands=[cmd], | ||
) | ) | ||
</ | </pre> | ||
Idea pratica: | Idea pratica: | ||
| Riga 180: | Riga 180: | ||
== Esempio dry run == | == Esempio dry run == | ||
< | <pre> | ||
pyinfra inventory.py deploy.py --dry | pyinfra inventory.py deploy.py --dry | ||
</ | </pre> | ||
Utile prima di un deploy reale. | Utile prima di un deploy reale. | ||
Versione delle 18:55, 29 mar 2026
Esempi Pyinfra
Questa pagina raccoglie esempi leggibili e progressivi: si parte dal minimo indispensabile e si arriva a pattern piu vicini a un uso reale.
Prima idea da fissare
Un progetto pyinfra semplice ha di solito almeno due file:
inventory.py deploy.py
L'inventory descrive i target. Il deploy descrive cosa fare.
Esempio base 1: esecuzione su host locali
Se vuoi solo capire la CLI:
pyinfra @local exec -- echo "hello world"
Questo serve quando vuoi verificare:
- che pyinfra sia installato
- che il runner funzioni
- che l'output arrivi correttamente
Esempio base 2: inventory minimale
web_servers = [
"web-01.example.net",
"web-02.example.net",
]
Qui hai solo una lista di host.
Esempio base 3: operation semplice
from pyinfra.operations import server
server.shell(
name="Show uptime",
commands=["uptime"],
)
Esecuzione:
pyinfra inventory.py deploy.py
Esempio base 4: installare pacchetti
from pyinfra.operations import apt
apt.packages(
name="Install packages",
packages=["vim", "curl"],
update=True,
)
Questo e un esempio di operation idempotente: se i pacchetti sono gia presenti, pyinfra non rifara cambiamenti inutili.
Esempio base 5: gestire file
from pyinfra.operations import files
files.file(
name="Ensure app log exists",
path="/var/log/app.log",
user="app",
group="app",
mode="644",
)
Esempio base 6: gestire servizi
from pyinfra.operations import systemd
systemd.service(
name="Ensure nginx is running",
service="nginx",
running=True,
enabled=True,
)
Esempio intermedio 1: dati host
Inventory:
app_servers = [
("app-01.example.net", {"install_nginx": True}),
("app-02.example.net", {"install_nginx": False}),
]
Deploy:
from pyinfra import host
from pyinfra.operations import apt
if host.data.get("install_nginx"):
apt.packages(
name="Install nginx",
packages=["nginx"],
update=True,
)
Qui usi Python per rendere il deploy diverso in base ai dati del target.
Esempio intermedio 2: gruppi
from pyinfra import host, local
from pyinfra.operations import server
if "web_servers" in host.groups:
local.include("tasks/web.py")
if "db_servers" in host.groups:
local.include("tasks/database.py")
server.shell(
name="Run everywhere",
commands=["hostname"],
)
Questo pattern e utile quando vuoi dividere la logica in file piu piccoli.
Esempio avanzato 1: deploy locale che richiama un helper Python
Questo e il pattern usato nel progetto Proxmox Web UI: pyinfra gira su @local ma esegue un helper esterno che contiene la logica vera.
#!/usr/bin/env python3
import os
import shlex
from pathlib import Path
from pyinfra.operations import server
BASE_DIR = Path(__file__).resolve().parents[1]
python_bin = os.environ.get("PYTHON_BIN", str(BASE_DIR / "venv" / "bin" / "python"))
helper = BASE_DIR / "lib" / "proxmox_ssh.py"
cmd = f"{shlex.quote(python_bin)} {shlex.quote(str(helper))}"
server.shell(
name=f"Create Proxmox VM {os.environ.get('VM_NAME', '')}",
commands=[cmd],
)
Idea pratica:
- pyinfra fa da orchestratore locale
- il file helper fa il lavoro specializzato
- le variabili ambiente passano i parametri del job
Esempio avanzato 2: usare pyinfra come backend di una UI
Nel caso GazziNet il flusso e:
- la UI riceve input dell'utente
- la UI valida i campi
- la UI crea un job con stato e log
- il job lancia
pyinfra @local deploy.py -y - pyinfra richiama un helper che esegue SSH su Proxmox
Questa soluzione e utile quando vuoi:
- separare presentazione e automazione
- conservare log testuali chiari
- evitare che il browser parli direttamente con Proxmox
Esempio avanzato 3: rete dinamica e validazione
Nel progetto VM automatiche la UI gestisce:
- DHCP oppure IP statico
- bridge selezionabile
- VLAN opzionale
- validazione preventiva bridge + VLAN
- ricerca del primo VMID libero
In questo caso pyinfra non decide la rete da solo: riceve i valori gia normalizzati e li passa al backend di provisioning.
Esempio dry run
pyinfra inventory.py deploy.py --dry
Utile prima di un deploy reale.
Pattern reali da ricordare
- tenere inventory e deploy in Git
- separare logica generale e helper specializzati
- validare input prima di lanciare pyinfra
- non mescolare segreti nei file versionati
- aggiungere sempre un modo semplice per verificare il risultato