Esempi Pyinfra: differenze tra le versioni

Da GazziNet.
Vai alla navigazione Vai alla ricerca
(Espansione esempi Pyinfra con casi base e avanzati)
(Aggiunta)
 
Riga 22: Riga 22:
* che il runner funzioni
* che il runner funzioni
* che l'output arrivi correttamente
* che l'output arrivi correttamente
Tradotto in pratica:
* se il comando parte, sai che <code>pyinfra</code> esiste davvero sul manager
* se l'operation viene eseguita, sai che il runner locale funziona
* se vedi <code>hello world</code>, sai che l'output viene raccolto correttamente
== Esempio concreto: devo controllare 10 server ==
Questo e uno dei casi piu utili per capire bene come ragiona pyinfra.
Scenario:
* hai una macchina '''manager'''
* da quella macchina vuoi controllare o configurare '''10 server target'''
=== Cosa deve esserci sul manager ===
Sul manager devono esserci:
* <code>Python</code>
* <code>pyinfra</code>
* i file di progetto, ad esempio <code>inventory.py</code> e <code>deploy.py</code>
* connettivita SSH verso i 10 server
* chiavi SSH oppure credenziali adatte
* eventuali permessi <code>sudo</code> se il deploy deve fare operazioni amministrative
In sintesi:
* il manager e la macchina da cui lanci i comandi
* il manager contiene la logica
* il manager non deve essere per forza uno dei 10 server target
=== Cosa deve esserci sui 10 server target ===
In generale pyinfra e '''agentless''', quindi non richiede un agente pyinfra installato sui target.
Di solito sui target servono:
* accesso SSH dal manager
* un utente valido con cui entrare
* eventuale <code>sudo</code> se devi amministrare il sistema
* shell e strumenti di base coerenti con quello che vuoi eseguire
In pratica:
* sui target '''non installi pyinfra'''
* sui target devi rendere possibile l'accesso e l'esecuzione delle operazioni richieste
=== Riepilogo semplice ===
* manager: installi pyinfra
* target: non installi pyinfra
* manager -> target: usi SSH
== Esempio con 10 server ==
Inventory minimale:
<pre>
all_servers = [
    "srv01.example.net",
    "srv02.example.net",
    "srv03.example.net",
    "srv04.example.net",
    "srv05.example.net",
    "srv06.example.net",
    "srv07.example.net",
    "srv08.example.net",
    "srv09.example.net",
    "srv10.example.net",
]
</pre>
Se vuoi dividere per gruppi:
<pre>
web_servers = [
    "srv01.example.net",
    "srv02.example.net",
    "srv03.example.net",
    "srv04.example.net",
    "srv05.example.net",
]
db_servers = [
    "srv06.example.net",
    "srv07.example.net",
]
misc_servers = [
    "srv08.example.net",
    "srv09.example.net",
    "srv10.example.net",
]
</pre>
== Primo test vero sui 10 server ==
Prima di fare configurazione, conviene fare un controllo innocuo.
Deploy:
<pre>
from pyinfra.operations import server
server.shell(
    name="Show hostname and uptime",
    commands=[
        "hostname",
        "uptime",
    ],
)
</pre>
Esecuzione dal manager:
<pre>
pyinfra inventory.py deploy.py
</pre>
Questo test serve a verificare:
* che il manager raggiunga tutti i target
* che l'utente SSH funzioni
* che pyinfra riesca a eseguire comandi su tutti i server
* che i risultati siano leggibili nell'output
== Esempio di controllo piu utile ==
Se vuoi controllare disco e un servizio:
<pre>
from pyinfra.operations import server
server.shell(
    name="Check disk",
    commands=["df -h /"],
)
server.shell(
    name="Check nginx service",
    commands=["systemctl is-active nginx || true"],
)
</pre>
Questo non modifica nulla, ma ti da gia una fotografia dei 10 server.
== Esempio di deploy reale ==
Se vuoi installare <code>vim</code> e assicurarti che <code>nginx</code> sia attivo:
<pre>
from pyinfra.operations import apt, systemd
apt.packages(
    name="Install vim",
    packages=["vim"],
    update=True,
)
systemd.service(
    name="Ensure nginx is running",
    service="nginx",
    running=True,
    enabled=True,
)
</pre>
In questo caso:
* sul manager hai solo pyinfra e i file del deploy
* sui target non hai pyinfra, ma hai accesso SSH e permessi adeguati
* pyinfra esegue il lavoro dal manager verso tutti i target
== Come pensarlo mentalmente ==
Formula utile:
* '''manager = cervello'''
* '''target = macchine su cui applicare le operazioni'''
Pyinfra gira nel cervello, non nelle braccia.


== Esempio base 2: inventory minimale ==
== Esempio base 2: inventory minimale ==

Versione attuale delle 19:21, 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

Tradotto in pratica:

  • se il comando parte, sai che pyinfra esiste davvero sul manager
  • se l'operation viene eseguita, sai che il runner locale funziona
  • se vedi hello world, sai che l'output viene raccolto correttamente

Esempio concreto: devo controllare 10 server

Questo e uno dei casi piu utili per capire bene come ragiona pyinfra.

Scenario:

  • hai una macchina manager
  • da quella macchina vuoi controllare o configurare 10 server target

Cosa deve esserci sul manager

Sul manager devono esserci:

  • Python
  • pyinfra
  • i file di progetto, ad esempio inventory.py e deploy.py
  • connettivita SSH verso i 10 server
  • chiavi SSH oppure credenziali adatte
  • eventuali permessi sudo se il deploy deve fare operazioni amministrative

In sintesi:

  • il manager e la macchina da cui lanci i comandi
  • il manager contiene la logica
  • il manager non deve essere per forza uno dei 10 server target

Cosa deve esserci sui 10 server target

In generale pyinfra e agentless, quindi non richiede un agente pyinfra installato sui target.

Di solito sui target servono:

  • accesso SSH dal manager
  • un utente valido con cui entrare
  • eventuale sudo se devi amministrare il sistema
  • shell e strumenti di base coerenti con quello che vuoi eseguire

In pratica:

  • sui target non installi pyinfra
  • sui target devi rendere possibile l'accesso e l'esecuzione delle operazioni richieste

Riepilogo semplice

  • manager: installi pyinfra
  • target: non installi pyinfra
  • manager -> target: usi SSH

Esempio con 10 server

Inventory minimale:

all_servers = [
    "srv01.example.net",
    "srv02.example.net",
    "srv03.example.net",
    "srv04.example.net",
    "srv05.example.net",
    "srv06.example.net",
    "srv07.example.net",
    "srv08.example.net",
    "srv09.example.net",
    "srv10.example.net",
]

Se vuoi dividere per gruppi:

web_servers = [
    "srv01.example.net",
    "srv02.example.net",
    "srv03.example.net",
    "srv04.example.net",
    "srv05.example.net",
]

db_servers = [
    "srv06.example.net",
    "srv07.example.net",
]

misc_servers = [
    "srv08.example.net",
    "srv09.example.net",
    "srv10.example.net",
]

Primo test vero sui 10 server

Prima di fare configurazione, conviene fare un controllo innocuo.

Deploy:

from pyinfra.operations import server

server.shell(
    name="Show hostname and uptime",
    commands=[
        "hostname",
        "uptime",
    ],
)

Esecuzione dal manager:

pyinfra inventory.py deploy.py

Questo test serve a verificare:

  • che il manager raggiunga tutti i target
  • che l'utente SSH funzioni
  • che pyinfra riesca a eseguire comandi su tutti i server
  • che i risultati siano leggibili nell'output

Esempio di controllo piu utile

Se vuoi controllare disco e un servizio:

from pyinfra.operations import server

server.shell(
    name="Check disk",
    commands=["df -h /"],
)

server.shell(
    name="Check nginx service",
    commands=["systemctl is-active nginx || true"],
)

Questo non modifica nulla, ma ti da gia una fotografia dei 10 server.

Esempio di deploy reale

Se vuoi installare vim e assicurarti che nginx sia attivo:

from pyinfra.operations import apt, systemd

apt.packages(
    name="Install vim",
    packages=["vim"],
    update=True,
)

systemd.service(
    name="Ensure nginx is running",
    service="nginx",
    running=True,
    enabled=True,
)

In questo caso:

  • sul manager hai solo pyinfra e i file del deploy
  • sui target non hai pyinfra, ma hai accesso SSH e permessi adeguati
  • pyinfra esegue il lavoro dal manager verso tutti i target

Come pensarlo mentalmente

Formula utile:

  • manager = cervello
  • target = macchine su cui applicare le operazioni

Pyinfra gira nel cervello, non nelle braccia.

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:

  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

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

Collegamenti