Python kubernetes client — StorageClass and PVC bind census
List provisioners and PVC phases before you trust a Bound claim.
<!-- hal:authoritative:yaml -->
List provisioners and PVC phases before you trust a Bound claim. Guessing the default class is how silent Immediate disks ship.
§I - Frame
Use the official Python kubernetes client to inventory StorageClasses and PersistentVolumeClaims. Pair with Ops AKS Azure Disk CSI work. Assume AKS-shaped names (disk.csi.azure.com, managed-csi) when present; still print whatever the cluster actually has.
Do not reopen boto3 EKS Pod Identity associations (09-21), Gateway HTTPRoute CustomObjects (09-18), or PSA namespace label walking (09-12). Tonight is storage.k8s.io StorageClass rows plus core PVC bind status.
§II - Client bootstrap
from kubernetes import client, config
from kubernetes.client.rest import ApiException
config.load_kube_config() # or load_incluster_config()
storage = client.StorageV1Api()
core = client.CoreV1Api()
DEFAULT_ANN = "storageclass.kubernetes.io/is-default-class"
Prefer a kubeconfig context pointed at an AKS lab. Catch ApiException and exit non-zero rather than inventing empty success. A census that hides API errors teaches the wrong instinct for Maghrib review.
§III - StorageClass census rows
def sc_rows():
rows = []
for sc in storage.list_storage_class().items:
ann = sc.metadata.annotations or {}
params = sc.parameters or {}
rows.append({
"name": sc.metadata.name,
"provisioner": sc.provisioner,
"reclaim": sc.reclaim_policy,
"bind_mode": sc.volume_binding_mode,
"is_default": ann.get(DEFAULT_ANN) == "true",
"sku": params.get("skuname") or params.get("storageaccounttype"),
"allow_expand": bool(sc.allow_volume_expansion),
})
return rows
Reviewer checks:
- Exactly one
is_default=True(Q14 instinct). Zero or two is a ship-stop comment. - AKS disk classes should show provisioner
disk.csi.azure.comwhen CSI is installed. bind_modeshould beWaitForFirstConsumeron modern managed-csi; flagImmediateon multi-zone pools.- Print
skuwhen parameters carryskuname(Azure Disk) without requiring every class to have it. - Count how many classes use Delete vs Retain reclaim; AKS built-ins are usually Delete.
§IV - PVC phase census
def pvc_rows(namespace=None):
if namespace:
items = core.list_namespaced_persistent_volume_claim(namespace).items
else:
items = core.list_persistent_volume_claim_for_all_namespaces().items
rows = []
for pvc in items:
spec, status = pvc.spec, pvc.status
req = None
if spec.resources and spec.resources.requests:
req = spec.resources.requests.get("storage")
cap = None
if status and status.capacity:
cap = status.capacity.get("storage")
rows.append({
"ns": pvc.metadata.namespace,
"name": pvc.metadata.name,
"phase": (status.phase if status else None),
"class": spec.storage_class_name,
"access": list(spec.access_modes or []),
"req": req,
"volume": spec.volume_name,
"capacity": cap,
})
return rows
Phase vocabulary that matters tonight: Pending (waiting on provisioner, bind mode, or consumer), Bound (has volume_name), Lost (rare; bad volume reference). For WaitForFirstConsumer, Pending with no Pod is expected; Bound without a Pod on Immediate is also expected. Do not treat Pending as failure until you know the bind mode and whether a consumer exists.
Optional enrichment: for Bound rows, core.read_persistent_volume(volume) and print persistent_volume_reclaim_policy plus CSI driver. Keep that optional; exit zero requires SC + PVC tables only.
§V - Report shape and done criteria
Print markdown a reviewer can skim:
# storage census
## storageclasses
- managed-csi | disk.csi.azure.com | Delete | WaitForFirstConsumer | default=True | sku=StandardSSD_LRS
- managed-csi-premium | disk.csi.azure.com | Delete | WaitForFirstConsumer | default=False | sku=Premium_LRS
## defaults
- count=1
## pvcs
- demo/app-data | Bound | class=managed-csi | RWO | req=20Gi | volume=pvc-...
## anomalies
- defaults!=1
- Immediate bind_mode on disk.csi.azure.com class
- Pending PVC whose class uses WaitForFirstConsumer and has no consumer Pod (informational)
Success: StorageClass table includes provisioner, reclaim, bind mode, default flag; default count is computed; PVC table includes phase, class, accessModes, requested size, bound volume name when Bound; exit zero on successful lists. Exit non-zero if API list fails. Optional --strict-default fails when default count is not 1 (useful CI gate after Cert Q14 patches).
Wire the script as a small module with if __name__ == "__main__" argparse for --namespace and --strict-default. Keep credentials out of the repo; rely on kubeconfig or in-cluster config only.
§VI - What this census is not
Do not call Azure identity APIs. Do not list Gateway or HTTPRoute objects. Do not walk PSA labels. Do not write terratest or Go. Do not apply manifests from Python tonight; Maghrib can deepen mutate paths later. Read-only inventory is enough to pair Ops and Cert.
§VII - Close
Ops declares AKS disk CSI classes and PVC bind edges. Python proves the live cluster still advertises those classes and shows claim phases. Pair Cert for Q14 StorageClass create/default and reclaim vocabulary. Maghrib owns quiz.html later.
Related
- Ops: AKS Azure Disk CSI
- Prior: Gateway HTTPRoute census (09-18)
- Cert: CKA StorageClass PVC PV
- Bootcamp: CKA Q14