Esempi Pyinfra: differenze tra le versioni
(Creazione pagina informativa su pyinfra) |
(Espansione esempi Pyinfra con casi base e avanzati) |
||
| Riga 1: | Riga 1: | ||
= Esempi Pyinfra = | = 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: | |||
<pre> | <pre> | ||
inventory.py | inventory.py | ||
| Riga 10: | Riga 10: | ||
</pre> | </pre> | ||
== | L'inventory descrive i target. Il deploy descrive cosa fare. | ||
< | |||
== Esempio base 1: esecuzione su host locali == | |||
Se vuoi solo capire la CLI: | |||
<syntaxhighlight lang="bash"> | |||
pyinfra @local exec -- echo "hello world" | |||
</syntaxhighlight> | |||
Questo serve quando vuoi verificare: | |||
* che pyinfra sia installato | |||
* che il runner funzioni | |||
* che l'output arrivi correttamente | |||
== Esempio base 2: inventory minimale == | |||
<syntaxhighlight lang="python"> | |||
web_servers = [ | web_servers = [ | ||
"web-01.example.net", | "web-01.example.net", | ||
"web-02.example.net", | "web-02.example.net", | ||
] | ] | ||
</syntaxhighlight> | |||
Qui hai solo una lista di host. | |||
== Esempio base 3: operation semplice == | |||
<syntaxhighlight lang="python"> | |||
from pyinfra.operations import server | |||
server.shell( | server.shell( | ||
| Riga 36: | Riga 41: | ||
commands=["uptime"], | commands=["uptime"], | ||
) | ) | ||
</ | </syntaxhighlight> | ||
Esecuzione: | Esecuzione: | ||
< | <syntaxhighlight lang="bash"> | ||
pyinfra inventory.py deploy.py | pyinfra inventory.py deploy.py | ||
</ | </syntaxhighlight> | ||
== Esempio base 4: installare pacchetti == | |||
<syntaxhighlight lang="python"> | |||
from pyinfra.operations import apt | |||
apt.packages( | |||
name="Install packages", | |||
packages=["vim", "curl"], | |||
update=True, | |||
) | |||
</syntaxhighlight> | |||
Questo e un esempio di operation idempotente: se i pacchetti sono gia presenti, pyinfra non rifara cambiamenti inutili. | |||
== Esempio base 5: gestire file == | |||
<syntaxhighlight lang="python"> | |||
from pyinfra.operations import files | |||
files.file( | |||
name="Ensure app log exists", | |||
path="/var/log/app.log", | |||
user="app", | |||
group="app", | |||
mode="644", | |||
) | |||
</syntaxhighlight> | |||
== Esempio base 6: gestire servizi == | |||
<syntaxhighlight lang="python"> | |||
from pyinfra.operations import systemd | |||
systemd.service( | |||
name=" | name="Ensure nginx is running", | ||
service="nginx", | |||
running=True, | |||
enabled=True, | |||
) | ) | ||
</ | </syntaxhighlight> | ||
== Esempio | == Esempio intermedio 1: dati host == | ||
Inventory: | Inventory: | ||
< | <syntaxhighlight lang="python"> | ||
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}), | ||
] | ] | ||
</ | </syntaxhighlight> | ||
Deploy: | Deploy: | ||
< | <syntaxhighlight lang="python"> | ||
from pyinfra import host | from pyinfra import host | ||
from pyinfra.operations import apt | from pyinfra.operations import apt | ||
| Riga 80: | Riga 106: | ||
update=True, | update=True, | ||
) | ) | ||
</ | </syntaxhighlight> | ||
Qui usi Python per rendere il deploy diverso in base ai dati del target. | |||
== Esempio | == Esempio intermedio 2: gruppi == | ||
< | <syntaxhighlight lang="python"> | ||
pyinfra | 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=" | name="Run everywhere", | ||
commands=["hostname"], | |||
) | ) | ||
</ | </syntaxhighlight> | ||
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 <code>@local</code> ma esegue un helper esterno che contiene la logica vera. | |||
<syntaxhighlight lang="python"> | |||
#!/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=" | name=f"Create Proxmox VM {os.environ.get('VM_NAME', '')}", | ||
commands=[cmd], | |||
) | ) | ||
</ | </syntaxhighlight> | ||
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 <code>pyinfra @local deploy.py -y</code> | |||
# 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 | == Esempio dry run == | ||
< | <syntaxhighlight lang="bash"> | ||
pyinfra inventory.py deploy.py --dry | pyinfra inventory.py deploy.py --dry | ||
</ | </syntaxhighlight> | ||
Utile prima di un deploy reale. | |||
== | == Pattern reali da ricordare == | ||
* tenere | * 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 | |||
== | == Collegamenti == | ||
* [ | * [[Pyinfra]] | ||
* [ | * [[Pyinfra/Deploy automatico VM Proxmox]] | ||
* [ | * [[Pyinfra/Implementazione deploy VM linea per linea]] | ||
* [ | * [[Confronto Ansible vs Pyinfra]] | ||
Versione delle 18:51, 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: <syntaxhighlight lang="bash"> pyinfra @local exec -- echo "hello world" </syntaxhighlight>
Questo serve quando vuoi verificare:
- che pyinfra sia installato
- che il runner funzioni
- che l'output arrivi correttamente
Esempio base 2: inventory minimale
<syntaxhighlight lang="python"> web_servers = [
"web-01.example.net", "web-02.example.net",
] </syntaxhighlight>
Qui hai solo una lista di host.
Esempio base 3: operation semplice
<syntaxhighlight lang="python"> from pyinfra.operations import server
server.shell(
name="Show uptime", commands=["uptime"],
) </syntaxhighlight>
Esecuzione: <syntaxhighlight lang="bash"> pyinfra inventory.py deploy.py </syntaxhighlight>
Esempio base 4: installare pacchetti
<syntaxhighlight lang="python"> from pyinfra.operations import apt
apt.packages(
name="Install packages", packages=["vim", "curl"], update=True,
) </syntaxhighlight>
Questo e un esempio di operation idempotente: se i pacchetti sono gia presenti, pyinfra non rifara cambiamenti inutili.
Esempio base 5: gestire file
<syntaxhighlight lang="python"> from pyinfra.operations import files
files.file(
name="Ensure app log exists", path="/var/log/app.log", user="app", group="app", mode="644",
) </syntaxhighlight>
Esempio base 6: gestire servizi
<syntaxhighlight lang="python"> from pyinfra.operations import systemd
systemd.service(
name="Ensure nginx is running", service="nginx", running=True, enabled=True,
) </syntaxhighlight>
Esempio intermedio 1: dati host
Inventory: <syntaxhighlight lang="python"> app_servers = [
("app-01.example.net", {"install_nginx": True}),
("app-02.example.net", {"install_nginx": False}),
] </syntaxhighlight>
Deploy: <syntaxhighlight lang="python"> from pyinfra import host from pyinfra.operations import apt
if host.data.get("install_nginx"):
apt.packages(
name="Install nginx",
packages=["nginx"],
update=True,
)
</syntaxhighlight>
Qui usi Python per rendere il deploy diverso in base ai dati del target.
Esempio intermedio 2: gruppi
<syntaxhighlight lang="python"> 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"],
) </syntaxhighlight>
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.
<syntaxhighlight lang="python">
- !/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],
) </syntaxhighlight>
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
<syntaxhighlight lang="bash"> pyinfra inventory.py deploy.py --dry </syntaxhighlight>
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