Modul 4 — Skriptování a automatizace
19. Práce s API a JSON/YAML v automatizačních skriptech
Volání REST API z Pythonu pomocí knihovny requests a čtení/zápis konfiguračních dat ve formátech JSON a YAML.
Úvod a kontext
Naprostá většina moderních nástrojů, které DevOps inženýr automatizuje —
cloudové platformy, monitoring, CI/CD systémy, Kubernetes — nabízí ovládání
přes REST API a ukládá konfiguraci ve formátu JSON nebo YAML.
Umět z Pythonu zavolat API, zpracovat odpověď a načíst/zapsat konfigurační
soubor je proto jedna z nejčastěji používaných dovedností v automatizačních
skriptech — mnohem častější než psaní vlastních algoritmů. Tato lekce
navazuje na základy Pythonu z minulé lekce a ukazuje, jak pracovat s daty,
která do skriptu přicházejí zvenčí.
Teorie
JSON a jeho reprezentace v Pythonu
JSON (JavaScript Object Notation) je textový formát pro strukturovaná
data — objekty ({}), pole ([]), řetězce, čísla, true/false,
null. Python má JSON podporu přímo ve standardní knihovně, modul json:
import json
data = {"jmeno": "web1", "port": 8080, "aktivni": True}
# Python objekt → JSON text
text = json.dumps(data, indent=2)
# JSON text → Python objekt (dict/list)
nacteno = json.loads(text)
print(nacteno["port"]) # 8080
json.dumps slouží k serializaci (Python → text), json.loads k
deserializaci (text → Python). Pro práci se soubory existují analogické
json.dump(data, soubor) a json.load(soubor), které rovnou čtou/zapisují
otevřený souborový objekt.
YAML a knihovna PyYAML
YAML je čitelnější alternativa k JSON, běžná v konfiguračních souborech
(Docker Compose, Kubernetes manifesty, GitHub Actions, Ansible). Na
rozdíl od JSON není součástí standardní knihovny — je potřeba doinstalovat
balíček pyyaml:
pip install pyyaml
Použití je analogické k modulu json:
import yaml
with open("konfig.yaml") as soubor:
data = yaml.safe_load(soubor)
print(data["databaze"]["host"])
with open("vystup.yaml", "w") as soubor:
yaml.safe_dump(data, soubor, allow_unicode=True)
yaml.safe_load (ne yaml.load) je důležité používat z bezpečnostních
důvodů — obyčejné yaml.load umí za určitých okolností spustit libovolný
Python kód zakódovaný v YAML souboru, pokud soubor pochází z nedůvěryhodného
zdroje. safe_load tuto možnost blokuje a měl by být výchozí volbou vždy,
pokud vývojář výslovně nepotřebuje pokročilé (a rizikové) vlastnosti.
Volání REST API pomocí knihovny requests
Standardní knihovna obsahuje modul urllib, ale v praxi se pro HTTP
požadavky téměř univerzálně používá balíček třetí strany requests — má
mnohem čitelnější API:
pip install requests
import requests
odpoved = requests.get(
"https://api.example.com/servers",
headers={"Authorization": "Bearer TOKEN"},
timeout=10,
)
odpoved.raise_for_status() # vyhodí výjimku, pokud stavový kód není 2xx
data = odpoved.json() # rovnou naparsuje JSON tělo odpovědi
Klíčové prvky:
timeout=10— request, který nikdy neskončí, dokáže zaseknout celý
skript; timeout je proto v produkčním kódu povinný, ne volitelný.raise_for_status()— bez tohoto volání skript tiše pokračuje i po
chybě (např.404nebo500), protožerequestssamo o sobě chybu
nevyhazuje jen kvůli špatnému stavovému kódu..json()— pohodlná zkratka zajson.loads(odpoved.text).
Odesílání dat (typicky vytváření nového záznamu přes API):
odpoved = requests.post(
"https://api.example.com/servers",
json={"jmeno": "web3", "port": 8080},
headers={"Authorization": "Bearer TOKEN"},
timeout=10,
)
odpoved.raise_for_status()
Parametr json= zajistí, že requests tělo požadavku automaticky
serializuje do JSON a nastaví správnou hlavičku Content-Type.
Zpracování chyb při volání API
Síťová volání selhávají mnohem častěji než lokální operace — výpadek sítě,
timeout, chybná autentizace, přetížený server. Robustní skript tyto stavy
ošetřuje explicitně:
try:
odpoved = requests.get("https://api.example.com/status", timeout=10)
odpoved.raise_for_status()
except requests.exceptions.Timeout:
print("API neodpovědělo včas.")
except requests.exceptions.HTTPError as chyba:
print(f"API vrátilo chybu: {chyba}")
except requests.exceptions.ConnectionError:
print("Nepodařilo se připojit k API.")
Praktický příklad
Skript, který načte seznam serverů z YAML konfigurace, zjistí přes fiktivní
monitorovací API jejich aktuální stav a výsledek zapíše jako JSON report:
#!/usr/bin/env python3
"""Zkontroluje stav serverů z konfigurace přes monitorovací API."""
import json
import sys
import requests
import yaml
KONFIG_SOUBOR = "servery.yaml"
VYSTUP_SOUBOR = "report.json"
API_URL = "https://monitoring.example.com/api/stav"
def nacti_servery(cesta: str) -> list:
with open(cesta) as soubor:
data = yaml.safe_load(soubor)
return data["servery"]
def zjisti_stav(jmeno: str) -> dict:
odpoved = requests.get(f"{API_URL}/{jmeno}", timeout=10)
odpoved.raise_for_status()
return odpoved.json()
def main() -> int:
try:
servery = nacti_servery(KONFIG_SOUBOR)
except FileNotFoundError:
print(f"Konfigurační soubor {KONFIG_SOUBOR} nenalezen.")
return 1
report = []
for server in servery:
try:
stav = zjisti_stav(server)
except requests.exceptions.RequestException as chyba:
print(f"Nepodařilo se zjistit stav {server}: {chyba}")
stav = {"stav": "neznamy"}
report.append({"server": server, **stav})
with open(VYSTUP_SOUBOR, "w") as soubor:
json.dump(report, soubor, indent=2, ensure_ascii=False)
print(f"Report uložen do {VYSTUP_SOUBOR} ({len(report)} serverů).")
return 0
if __name__ == "__main__":
sys.exit(main())
Odpovídající konfigurace servery.yaml:
servery:
- web1
- web2
- db1
Ukázka je záměrně strukturovaná do malých funkcí (nacti_servery,
zjisti_stav) — usnadňuje to testování jednotlivých kroků odděleně a
znovupoužití v jiném skriptu.
Shrnutí
Moduly json (vestavěný) a yaml (balíček pyyaml, vždy přes
safe_load) pokrývají naprostou většinu práce s konfiguračními a
výměnnými daty v automatizaci. Knihovna requests je standardní volba
pro volání REST API — vždy s explicitním timeout a raise_for_status(),
aby chyby nezůstaly tiše přehlédnuté. Kombinace obou (načtení konfigurace
z YAML, zavolání API, zápis výsledku do JSON) je jeden z nejběžnějších
vzorů automatizačních skriptů v provozu.
Kontrolní otázky
- Proč se v produkčním kódu vždy používá
yaml.safe_loadmísto
yaml.load? - Co se stane, pokud
requests.get(...)zavoláte bez parametru
timeout, a proč je to problém pro automatizační skript spouštěný z
cronu? - K čemu slouží
raise_for_status()a co by se stalo, kdyby skript toto
volání vynechal a API vrátilo chybu500? - Upravte ukázkový skript tak, aby kromě zápisu do
report.jsonvypsal
na konci i počet serverů, u kterých se stav nepodařilo zjistit
(stav: "neznamy").
Lekce na sebe nejsou zamčené — libovolnou lekci můžete otevřít i označit jako hotovou v jakémkoliv pořadí.