Esempi Pyinfra: differenze tra le versioni

Da GazziNet.
Vai alla navigazione Vai alla ricerca
(Creazione pagina informativa su pyinfra)
 
(Espansione esempi Pyinfra con casi base e avanzati)
Riga 1: Riga 1:
= Esempi Pyinfra =
= Esempi Pyinfra =


Pagina operativa con esempi minimi e riusabili per iniziare a usare '''pyinfra'''.
Questa pagina raccoglie esempi leggibili e progressivi: si parte dal minimo indispensabile e si arriva a pattern piu vicini a un uso reale.


== Struttura minima ==
== Prima idea da fissare ==
Esempio di file:
Un progetto pyinfra semplice ha di solito almeno due file:
<pre>
<pre>
inventory.py
inventory.py
Riga 10: Riga 10:
</pre>
</pre>


== Inventory semplice ==
L'inventory descrive i target. Il deploy descrive cosa fare.
<pre>
 
== 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>


db_servers = [
Qui hai solo una lista di host.
    ("db-01.example.net", {"install_postgres": True}),
]
</pre>
 
== Deploy semplice ==
<pre>
from pyinfra.operations import apt, server


apt.packages(
== Esempio base 3: operation semplice ==
    name="Install packages",
<syntaxhighlight lang="python">
    packages=["vim", "curl"],
from pyinfra.operations import server
    update=True,
)


server.shell(
server.shell(
Riga 36: Riga 41:
     commands=["uptime"],
     commands=["uptime"],
)
)
</pre>
</syntaxhighlight>


Esecuzione:
Esecuzione:
<pre>
<syntaxhighlight lang="bash">
pyinfra inventory.py deploy.py
pyinfra inventory.py deploy.py
</pre>
</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>


== Esempio con gruppi ==
Questo e un esempio di operation idempotente: se i pacchetti sono gia presenti, pyinfra non rifara cambiamenti inutili.
<pre>
from pyinfra import host, local
from pyinfra.operations import server


if 'web_servers' in host.groups:
== Esempio base 5: gestire file ==
    local.include('tasks/web.py')
<syntaxhighlight lang="python">
from pyinfra.operations import files


if 'db_servers' in host.groups:
files.file(
     local.include('tasks/database.py')
    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


server.shell(
systemd.service(
     name="Run everywhere",
     name="Ensure nginx is running",
     commands=["hostname"],
     service="nginx",
    running=True,
    enabled=True,
)
)
</pre>
</syntaxhighlight>


== Esempio con dati host ==
== Esempio intermedio 1: dati host ==
Inventory:
Inventory:
<pre>
<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}),
]
]
</pre>
</syntaxhighlight>


Deploy:
Deploy:
<pre>
<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,
     )
     )
</pre>
</syntaxhighlight>
 
Qui usi Python per rendere il deploy diverso in base ai dati del target.


== Esempio local machine ==
== Esempio intermedio 2: gruppi ==
<pre>
<syntaxhighlight lang="python">
pyinfra @local exec -- echo "hello world"
from pyinfra import host, local
</pre>
from pyinfra.operations import server


== Esempio su container Docker ==
if "web_servers" in host.groups:
<pre>
    local.include("tasks/web.py")
pyinfra @docker/ubuntu:22.04 exec -- uname -a
</pre>


== Esempio installazione file ==
if "db_servers" in host.groups:
<pre>
    local.include("tasks/database.py")
from pyinfra.operations import files


files.file(
server.shell(
     name="Ensure app log exists",
     name="Run everywhere",
     path="/var/log/app.log",
     commands=["hostname"],
    user="app",
    group="app",
    mode="644",
)
)
</pre>
</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


== Esempio service management ==
BASE_DIR = Path(__file__).resolve().parents[1]
<pre>
python_bin = os.environ.get("PYTHON_BIN", str(BASE_DIR / "venv" / "bin" / "python"))
from pyinfra.operations import systemd
helper = BASE_DIR / "lib" / "proxmox_ssh.py"
cmd = f"{shlex.quote(python_bin)} {shlex.quote(str(helper))}"


systemd.service(
server.shell(
     name="Ensure nginx is running",
     name=f"Create Proxmox VM {os.environ.get('VM_NAME', '')}",
    service="nginx",
     commands=[cmd],
    running=True,
     enabled=True,
)
)
</pre>
</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-run ==
== Esempio dry run ==
<pre>
<syntaxhighlight lang="bash">
pyinfra inventory.py deploy.py --dry
pyinfra inventory.py deploy.py --dry
</pre>
</syntaxhighlight>
 
Utile prima di un deploy reale.


== Note pratiche ==
== Pattern reali da ricordare ==
* tenere `inventory.py` e `deploy.py` in Git
* tenere inventory e deploy in Git
* usare `host.data` per differenziare host simili
* separare logica generale e helper specializzati
* separare task complessi in file inclusi
* validare input prima di lanciare pyinfra
* usare `--dry` prima dei deploy reali
* non mescolare segreti nei file versionati
* aggiungere sempre un modo semplice per verificare il risultato


== Link ufficiali ==
== Collegamenti ==
* [https://docs.pyinfra.com/en/3.x/getting-started.html Getting Started]
* [[Pyinfra]]
* [https://docs.pyinfra.com/en/3.x/inventory-data.html Inventory & Data]
* [[Pyinfra/Deploy automatico VM Proxmox]]
* [https://docs.pyinfra.com/en/3.x/examples/groups_roles.html Groups & Roles]
* [[Pyinfra/Implementazione deploy VM linea per linea]]
* [https://docs.pyinfra.com/en/3.x/using-operations.html Using Operations]
* [[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">

  1. !/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:

  1. la UI riceve input dell'utente
  2. la UI valida i campi
  3. la UI crea un job con stato e log
  4. il job lancia pyinfra @local deploy.py -y
  5. 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

Collegamenti