Settembre 2026
Il provider Terraform di Pathly, in pratica
È pubblicato sul registro. Ecco i file che si scrivono davvero: il più piccolo che serva a qualcosa, un intero parco descritto come un dato, e la ripresa di un monitoraggio creato a mano.
Installare
Il provider si chiama pathlyhq/pathly sul registro pubblico. Non c’è nulla da compilare né da depositare in un mirror: basta la dichiarazione di versione, e il comando di inizializzazione lo scarica. Il vincolo ~> 0.1 accetta le correzioni e rifiuta un’eventuale 0.2, che è l’impostazione giusta finché lo schema non è fissato da una 1.0.
terraform {
required_version = ">= 1.6"
required_providers {
pathly = {
source = "pathlyhq/pathly"
version = "~> 0.1"
}
}
}
# Nessun argomento: la chiave viene da PATHLY_API_TOKEN.
provider "pathly" {}Il blocco provider è vuoto, e non è una svista. La chiave si legge dalla variabile d’ambiente PATHLY_API_TOKEN. Passata tramite una variabile Terraform, finirebbe in chiaro nel file di stato, che ci si dimentica sempre di cifrare prima di averlo già inviato da qualche parte. Il provider rifiuta inoltre di parlare in http con qualcosa di diverso da localhost: la chiave viaggia in un’intestazione di autorizzazione, sarebbe leggibile da tutti gli intermediari.
Il file più piccolo che serva a qualcosa
Uno scenario, un indirizzo, un intervallo e un testo che ci si aspetta di trovare nella pagina. Quest’ultimo punto fa la differenza tra monitorare un server e monitorare un sito: una pagina di errore applicativo risponde benissimo in HTTP 200, e solo il testo atteso la smaschera.
resource "pathly_scenario" "site" {
name = "Home page"
url = "https://shop.example.com"
interval_sec = 300
expect_text = "Our products"
tags = ["prod"]
}Un parco descritto come un dato
Oltre tre o quattro percorsi, un blocco per risorsa diventa un elenco da rileggere a ogni aggiunta. Descriverli in una variabile e iterarci sopra cambia la natura del file: aggiungere un percorso diventa una riga di dati, e le regole su soglia, cartella ed etichetta restano le stesse per tutti senza doverci pensare.
resource "pathly_scenario" "journey" {
for_each = var.journeys
name = each.value.name
url = each.value.url
interval_sec = each.value.interval_sec
expect_text = each.value.expect_text
# Una soglia di latenza per percorso: il pagamento tollera
# meno di una home page servita dalla cache.
max_latency_ms = each.value.max_latency_ms
expected_status = 200
severity = each.value.severity
tags = concat(["terraform", var.environment], each.value.tags)
}
# Un obiettivo di disponibilità per percorso critico, che
# avvisa all'80% del budget di errore speso: oltre, resta
# troppo poco margine per il resto del mese.
resource "pathly_sla_target" "objective" {
for_each = {
for key, j in var.journeys : key => j if j.severity == "critical"
}
scenario_id = pathly_scenario.journey[each.key].id
objective_pct = 99.9
window_days = 30
exclude_maintenance = true
warn_at_budget_ratio = 0.8
}L’obiettivo di disponibilità esclude le finestre di manutenzione, il che ha senso solo se queste finestre esistono anche nel codice. Una manutenzione dichiarata da una parte e un obiettivo che la ignora dall’altra producono un budget di errore speso per un’interruzione annunciata, cioè un avviso che punisce un’operazione pianificata.
# Backup settimanale: gli errori in questa finestra
# non consumano il budget di errore.
resource "pathly_maintenance_window" "backup" {
weekday = 7 # domenica
start_minute = 3 * 60
duration_min = 120
reason = "Weekly backup"
}Individuare ciò che è stato creato a mano
È l’uso più utile della fonte di dati, e quello a cui si pensa meno. Rilegge l’inventario così come lo vede l’API. Confrontato con ciò che il codice dichiara, lo scarto nomina gli scenari creati nella console e assenti dai file: quelli che nessuno rivede, e che nessuno eliminerà quando un ambiente verrà smantellato.
data "pathly_scenarios" "prod" {
filter_tag = var.environment
depends_on = [pathly_scenario.journey]
}
output "scenarios_outside_terraform" {
value = [
for s in data.pathly_scenarios.prod.scenarios : s.name
if !contains([for j in pathly_scenario.journey : j.id], s.id)
]
}Lo stesso ragionamento vale per i valori che l’API non restituisce mai. La destinazione di un webhook si scrive e non si rilegge: al suo posto, un’impronta di dodici caratteri, che cambia appena cambia l’indirizzo. Non permette di ricostruire la destinazione, e basta per vedere nel plan che è stata modificata altrove.
output "webhook_fingerprint" {
value = pathly_webhook.alerts.url_fingerprint
}Riprendere un monitoraggio esistente
Nessuno ricrea il proprio parco per passare al codice, e il provider non lo chiede. Ogni risorsa si importa tramite il suo identificativo, quello che compare nell’indirizzo dello scenario nella console. Dopo l’importazione, il plan mostra lo scarto tra l’esistente e ciò che il file descrive: finché non è vuoto, l’apply modificherà lo scenario sul posto invece di crearne un secondo.
terraform import pathly_scenario.checkout mon_01H8ZK…
Il criterio che decide se tutto questo è utilizzabile sta in una frase: dopo un apply, il plan successivo deve essere vuoto. Un provider che propone una modifica a ogni passaggio insegna molto presto ai suoi utenti a non leggere più i suoi plan, e il giorno in cui il plan dice qualcosa di vero, nessuno lo vede. È il lavoro meno visibile del provider, ed è quello su cui i suoi test insistono di più.
Cosa il provider non farà mai
- Emettere o revocare una chiave API: una chiave capace di farlo annulla gli ambiti di tutte le altre, e un file di configurazione non deve potersi allargare da solo.
- Invitare un membro: è la stessa escalation per una via traversa, perché l’account creato emetterà poi le chiavi che vuole.
- Cambiare piano o toccare la fatturazione: una pipeline di integrazione continua non deve poter impegnare una spesa ricorrente.
Queste assenze non sono funzionalità in ritardo. Un provider che copre tutto finisce per richiedere una chiave che può tutto, e quella chiave resta poi nelle variabili di una pipeline lette da più persone di quanto si creda. Ciò che manca qui manca apposta, e si fa nell’interfaccia, da parte di una persona identificata.