Hedronite · Dev Lesson · Polyglot-Dev / Python · Fri 2026-09-18

Python kubernetes client — Gateway API HTTPRoute census

List parentRefs before you cut over Ingress. Guessing Accepted parents is how silent 404s survive review.

Lesson Class: Dev (Python + kubernetes client + Gateway API)
Paired Ops: GKE Gateway API GatewayClass + HTTPRoute
Paired Cert: CKA Gateway API migrate Ingress
Grounding: CKA Q11 · Poulton Ch.8
List
CustomObjectsApi gateways + httproutes.
Accept
Parents conditions Accepted=True.
Backend
backendRefs name/port/namespace.
Ship a table ops can sort by Accepted parent and empty addresses.

<!-- hal:authoritative:yaml -->

List parentRefs before you cut over Ingress. Guessing which HTTPRoutes are Accepted is how silent 404s survive review.

§I — Frame

Use the official Python kubernetes client CustomObjectsApi to inventory Gateway and HTTPRoute objects under gateway.networking.k8s.io. Pair with Ops GKE Gateway work. Do not reopen PSA label walking (09-12) or NetworkPolicy listing (09-09).

§II — Client bootstrap

from kubernetes import client, config

config.load_kube_config()
cust = client.CustomObjectsApi()
GROUP = "gateway.networking.k8s.io"
VERSION = "v1"

Prefer v1 when the cluster CRDs are v1. Fall back to v1beta1 only if list calls 404 on v1.

§III — Gateway census row

gws = cust.list_cluster_custom_object(GROUP, VERSION, "gateways")
rows = []
for item in gws.get("items", []):
    md = item["metadata"]
    spec = item.get("spec", {})
    status = item.get("status", {})
    listeners = [
        {
            "name": L.get("name"),
            "port": L.get("port"),
            "protocol": L.get("protocol"),
            "hostname": L.get("hostname"),
        }
        for L in spec.get("listeners", [])
    ]
    addrs = [a.get("value") for a in status.get("addresses", [])]
    rows.append({
        "ns": md["namespace"],
        "name": md["name"],
        "class": spec.get("gatewayClassName"),
        "listeners": listeners,
        "addresses": addrs,
    })

Print WARN when addresses is empty on an external class you expect to be live.

§IV — HTTPRoute parent and backend census

routes = cust.list_cluster_custom_object(GROUP, VERSION, "httproutes")
for item in routes.get("items", []):
    md = item["metadata"]
    spec = item.get("spec", {})
    status = item.get("status", {})
    parents = spec.get("parentRefs", [])
    accepted = []
    for p in status.get("parents", []):
        conds = p.get("conditions", [])
        ok = any(c.get("type") == "Accepted" and c.get("status") == "True" for c in conds)
        accepted.append({"parent": p.get("parentRef"), "accepted": ok})
    backends = []
    for rule in spec.get("rules", []):
        for b in rule.get("backendRefs", []):
            backends.append({"name": b.get("name"), "port": b.get("port"), "ns": b.get("namespace")})
    print({
        "ns": md["namespace"],
        "name": md["name"],
        "parentRefs": parents,
        "accepted": accepted,
        "backends": backends,
        "hostnames": spec.get("hostnames"),
    })

Highest priority WARN: HTTPRoute with parentRefs set but no Accepted=True parent, or backendRefs pointing at a Service name that does not exist in the route namespace.

§V — What not to invent

§VI — Relation to Cert

Cert trains migrating an Ingress named web into Gateway web-gateway and HTTPRoute web-route (Bootcamp Q11). This census finds live Gateway API objects (and orphans) before and after that cutover pattern on GKE.

§VII — Closing

Ship a table ops can sort by Accepted parent and empty addresses. Flag routes that still have no programmed parent. Leave mutation for a change window.

Related