1. Lernziele
- REST, Webhook, WebSocket und Terraform passend wählen
- Organisation-, Site- und Device-Scope korrekt adressieren
- Cloudregion und Tokenart sicher bestimmen
- HTTP, JSON, Pagination und Rate Limits beherrschen
- idempotente Soll-Ist-Skripte erstellen
- Dry Run, Canary, Tests und Postconditions einbauen
- Secrets, State und Audit sicher betreiben
- Webhook-Ereignisse entkoppelt und duplikatsicher verarbeiten
- Drift, Teilausfall und Rollback beherrschen
2. Automationsmodell
Mist ist laut Juniper API-driven. Technische Automatisierbarkeit ersetzt aber keine Scope-, Risiko- und Wirkungsprüfung.
| Stufe | Beispiel | Risiko |
|---|---|---|
| Read-only | Inventar/SLE | unvollständige Daten |
| Assisted | Plan mit Freigabe | veralteter Plan |
| Closed-loop | Event → Korrektur | Fehltrigger |
| IaC | deklarative Sites/WLANs | Drift/Ownership |
3. Werkzeugvergleich
| Werkzeug | Modell | Geeignet |
|---|---|---|
| REST API | Pull/Request | CRUD, Inventar, Statistik |
| Webhook | Push/POST | Alarme, Events, Location |
| WebSocket | Stream | Live-Daten, BLE, PCAP |
| Terraform | deklarativ | Day 0/1 und Drift |
| Postman/API Explorer | interaktiv | Prototyp und Payloadprüfung |
| Python/Go/PowerShell | programmierbar | Workflows und Integration |
4. Objekt- und Scope-Modell
| Scope | ID | Objekte |
|---|---|---|
| MSP | msp_id | Mandanten |
| Organization | org_id | Sites, Inventory, Templates |
| Site | site_id | WLANs, Geräte, SLEs |
| Device | ID/MAC je Endpoint | AP, Switch, Gateway |
| Template/Profile | UUID | WLAN-, Switch-, Network-Template |
5. Cloudregion und API-Host
| Portal | REST API | Region |
|---|---|---|
manage.mist.com | api.mist.com | Global 01 |
manage.eu.mist.com | api.eu.mist.com | EMEA 01 |
manage.gc3.mist.com | api.gc3.mist.com | EMEA 02 |
manage.ac6.mist.com | api.ac6.mist.com | EMEA 03 |
manage.gc6.mist.com | api.gc6.mist.com | EMEA 04 |
Der Host ist Konfiguration, keine hart codierte Konstante. Die vollständige aktuelle Liste liefert Juniper.
6. Authentisierung und Tokenwahl
Authorization: Token MIST_API_TOKEN_VALUE
Accept: application/json
Content-Type: application/json| Merkmal | Org Token | User Token |
|---|---|---|
| Scope | eine Organisation | Benutzerzugriffe |
| Rechte | Token-Access-Level | Benutzerrechte |
| Rate Limit | pro Org Token | kumuliert pro Benutzer |
| Einsatz | Dienst/App | persönliches Skript |
7. REST und HTTP
| Absicht | Methode | Kontrolle |
|---|---|---|
| Create | POST | Read-before-Create |
| Read | GET | Pagination/Filter |
| Update | PUT | Endpoint- und Write-Schema |
| Delete | DELETE | Referenzen/Freigabe |
https://API_HOST/api/v1/sites/SITE_ID/stats/devices/DEVICE_IDPartieller oder vollständiger Update ergibt sich aus der jeweiligen API-Referenz, nicht allein aus der Methode.
8. cURL-Grundmuster
export MIST_API_HOST="api.eu.mist.com"
export MIST_ORG_ID="00000000-0000-0000-0000-000000000000"
curl --fail-with-body --silent --show-error \
--connect-timeout 5 --max-time 30 \
-H "Authorization: Token $MIST_APITOKEN" \
-H "Accept: application/json" \
"https://$MIST_API_HOST/api/v1/orgs/$MIST_ORG_ID/sites?limit=1000"Das Beispiel enthält Platzhalter. Endpoint und Schema werden vor Nutzung in der aktuellen Referenz geprüft.
9. Robuster Python-Basisklient
import os, random, time, requests
base = "https://" + os.environ["MIST_API_HOST"] + "/api/v1"
session = requests.Session()
session.headers.update({
"Authorization": "Token " + os.environ["MIST_APITOKEN"],
"Accept": "application/json",
"Content-Type": "application/json",
"User-Agent": "mist-automation/1.0"
})
def api(method, path, **kwargs):
for attempt in range(5):
r = session.request(method, base + path, timeout=(5, 30), **kwargs)
if r.status_code == 429:
time.sleep(int(r.headers.get("Retry-After", "60")) + random.random())
continue
if 500 <= r.status_code < 600:
time.sleep(min(2 ** attempt + random.random(), 30))
continue
r.raise_for_status()
return r
raise RuntimeError("request failed after retries")Write-Retries brauchen Fachlogik gegen Doppelwirkung. Nach einem Timeout wird zuerst der Istzustand gelesen.
10. HTTP-Fehler behandeln
| Code | Bedeutung | Reaktion |
|---|---|---|
| 200 | API erfolgreich | Postcondition prüfen |
| 400 | Payload falsch | Schema korrigieren |
| 401 | Auth falsch | Token/Host prüfen |
| 403 | Recht fehlt | Scope/Access Level |
| 404 | Objekt/Endpoint fehlt | ID/Deprecation |
| 429 | Rate Limit | Retry-After |
| 5xx | Serverfehler | begrenzter Backoff |
11. Pagination vollständig lesen
def get_all(path, limit=1000):
page, result = 1, []
while True:
r = api("GET", path, params={"limit": limit, "page": page})
body = r.json()
batch = body if isinstance(body, list) else body.get("results", [])
if not isinstance(batch, list):
raise TypeError("unexpected response schema")
result.extend(batch)
total = int(r.headers.get("X-Page-Total", len(result)))
if not batch or len(result) >= total or len(batch) < limit:
return result
page += 1Juniper nennt häufig 100 als Default und 1000 als Maximum. Manche Endpoints nutzen einen next-Verweis. Der konkrete Endpoint entscheidet.
12. Rate Limit und Backoff
Juniper dokumentiert derzeit 5.000 Calls je Stunde. Der Login-Endpoint wird nach wenigen Fehlversuchen früher begrenzt.
- Org-Level statt vieler Site-Abfragen
- Webhook statt Event-Polling
- stabile Referenzdaten cachen
- Retry-After und Jitter respektieren
- Parallelität begrenzen
13. Idempotenz
| Muster | Wirkung |
|---|---|
| Read before Create | kein doppeltes Objekt |
| Compare before Update | NOOP statt unnötigem Write |
| Postcondition | Wirkung nachweisen |
| Operation Ledger | Run-ID und Teilfortschritt |
| Ambiguous Result | nach Timeout Ist prüfen |
| Delete Guard | Owner, Scope und Freigabe |
14. Reconciliation Loop
desired = load_and_validate("desired/site.json")
current = read_current(desired["id"])
diff = normalized_diff(current, desired)
if not diff:
print("NOOP")
elif dry_run:
print_plan(diff)
else:
require_approval(diff)
backup(current)
apply(build_write_payload(desired))
verify(desired)15. Bulk und Parallelität
| Risiko | Kontrolle |
|---|---|
| Blast Radius | Canary/Batchlimit |
| Rate Limit | begrenzter Workerpool |
| Teilfortschritt | Checkpoint/Resume |
| Reihenfolge | Dependency Graph |
| Eventual Consistency | begrenztes Verify-Polling |
| abweichende Sites | Preflight-Matrix |
16. Webhooks
| REST | Webhook |
|---|---|
| Client fragt | Mist pusht POST |
| API-Budget | kein REST-Call-Limit laut Juniper |
| beliebige Abfrage | definierte Topics |
| Polling-Latenz | ereignisnah |
Org- und Site-Webhooks liefern unter anderem Alarme, Device Events oder Location-Daten. Kritische Workflows werden entkoppelt.
17. Produktionsreifer Receiver
def receive(request):
raw = request.get_data(cache=False)
verify_source_and_secret(request.headers, raw)
event = validate_event(raw)
key = stable_event_key(event)
if not store.seen(key):
queue.publish({"key": key, "event": event})
store.mark_seen(key)
return "", 204- schnell bestätigen, asynchron arbeiten
- Duplikate und Reihenfolge tolerieren
- Payloadgröße und Schema begrenzen
- Dead Letter Queue und Replay
- keine Produktivdaten an öffentliche Tester
18. WebSockets
wss://api-ws.eu.mist.com/api-ws/v1/stream
{"subscribe": "/sites/SITE_ID/pcaps"}| Pflicht | Kontrolle |
|---|---|
| Region | passender api-ws-Host |
| Auth | dokumentierte Tokenmethode |
| Subscription | Site und Channel |
| Reconnect | Backoff und Resubscribe |
| Backpressure | Queue/Consumerlimit |
Use Cases: Live-Dashboard, BLE, Device-Statistiken und PCAP-Streaming.
19. Terraform Provider
terraform {
required_providers {
mist = {
source = "Juniper/mist"
version = "~> 0.9"
}
}
}
provider "mist" { host = var.mist_api_host }
resource "mist_site" "berlin" {
org_id = var.org_id
name = "DE-BER-01"
country_code = "DE"
timezone = "Europe/Berlin"
}20. Terraform State und Ownership
| Thema | Regel |
|---|---|
| Remote State | verschlüsselt, gesperrt, versioniert |
| Secrets | State als sensibel behandeln |
| Import | bestehende Ressourcen importieren |
| Ownership | nicht parallel Portal/Skript/Terraform |
| Destroy | Schutz und manuelle Freigabe |
State ist keine vollständige Mist-Sicherung.
21. GitOps und CI/CD
Formatter, Linter, Types, Secret Scan.
Unit, Contract und Mock.
begrenzte Integration.
Diff und Blast Radius.
Vier-Augen-Freigabe.
repräsentative Site.
Stop-KPI überwachen.
Run-ID, Diff, SLE, Ergebnis.
22. Secrets und Least Privilege
| Anti-Pattern | Alternative |
|---|---|
| Token in Git/HCL | Vault oder CI Secret Store |
| Header im Debuglog | Redaction |
| ein Admin-Token | Token je Dienst, Minimalrecht |
| Prod-Token im Notebook | Test-Org und Testtoken |
| keine Rotation | Owner, Turnus, Sperrprozess |
# .gitignore
.env
*.tfstate
*.tfstate.*
secrets/23. Teststrategie
| Test | Beweis |
|---|---|
| Unit | Diff/Normalizer |
| Contract | Response verarbeitbar |
| Mock | 429/500/Timeout |
| Integration | echte Test-Org |
| Idempotency | zweiter Lauf NOOP |
| Canary | begrenzte Produktion |
| Regression | Provider/API-Upgrade |
24. Logging und Audit
| Loggen | Nicht loggen |
|---|---|
| Run-ID, Scope, Objekt-ID | Token/Cookies |
| Diff, Status, Dauer | unnötige Personendaten |
| Retry und Postcondition | ungefilterte Debugantwort |
Metriken: Request Rate, 2xx/4xx/5xx, 429, Retry-Anzahl, Queue-Alter, Laufzeit, NOOP/Change/Failure und Verify-Fehler.
25. Backup und Rollback
| Vor Änderung | Nach Fehler |
|---|---|
| Ist exportieren | Teilfortschritt bestimmen |
| Write-Felder isolieren | alten Body nicht blind schreiben |
| Abhängigkeiten | sicher kompensieren |
| Canary/Stop | weitere Wellen stoppen |
| Postconditions | Rollback verifizieren |
Cloud-Änderungen über mehrere Ressourcen sind nicht automatisch transaktional.
26. Use Cases
| Fall | Werkzeug | Guardrail |
|---|---|---|
| Site-Baseline | Terraform/Reconciler | Canary |
| WLAN-Rollout | Template/IaC | VLAN/AAA |
| Inventar | REST | Pagination |
| SLE-Export | REST | Zeit/Rate |
| Device-Down-Ticket | Webhook/Queue | Dedupe |
| Zone Entry | Location Webhook | Datenschutz |
| Live-PCAP | WebSocket | Zugriff/Retention |
| Compliance | Read-only Script | versionierter Sollzustand |
27. Systematische Fehlersuche
| Symptom | Prüfung |
|---|---|
| 401 | Token-Prefix, Wert, Region |
| 403 | Tokenart/Access Level |
| 404 | Host, Path, ID, Deprecation |
| 400 | JSON und Write-Schema |
| 429 | Budget und Retry-After |
| nur 100 Objekte | Pagination |
| Dubletten | POST-Retry |
| Terraform Replace | ForceNew, Import, Drift |
| Webhook mehrfach | Dedupe-Key |
| 200 ohne Wirkung | Postcondition/Devicezustand |
28. Produktionscheckliste
Code
- Host variabel
- Tokenart bewusst
- Timeouts
- Status/JSON
- Pagination
- 429/Backoff
- Idempotenz
- Dry Run
- Postcondition
Betrieb
- Least Privilege
- Secret Store
- Test/Prod getrennt
- Canary/Batch
- Audit/Run-ID
- Backup/Kompensation
- Queue/Dedupe
- Monitoring
- Runbook
Häufige Fehlannahmen
| Aussage | Bewertung | Richtig |
|---|---|---|
| API-driven heißt risikofrei. | Falsch | Scope/Wirkung prüfen. |
| api.mist.com passt immer. | Falsch | Region bestimmt Host. |
| 200 beweist Funktion. | Falsch | Postcondition fehlt. |
| Retry ist immer sicher. | Falsch | POST kann doppeln. |
| Erste Seite ist alles. | Falsch | Pagination. |
| Webhook exakt einmal. | Nicht annehmen | Dedupe. |
| State ist Backup. | Falsch | nur Terraform-Sicht. |
29. Offizielle Grundlagen
- Mist Automation Guide
- RESTful API Overview
- API Endpoints and Regions
- API Tokens
- Rate Limit
- Pagination
- HTTP Codes
- Webhooks
- WebSockets
- Terraform Integration
- Mist Provider
Fachstand: August 2026. API-Pfade, Schemas, Limits, Topics und Providerressourcen ändern sich. Maßgeblich sind aktuelle API Reference, Cloudregion, gepinnte Versionen und Tests in der eigenen Organisation.