kit/preflight/vexa_preflight.py · audience: customer
When you use this
Run before the first sync and before every upgrade, to answer “will this cluster run what the channel delivers” while there is still time to fix the answer. Every check is anchored to a failure seen in a real customer cluster; the first sync is the wrong moment to discover a taint.Usage
Emitted frompython3 kit/preflight/vexa_preflight.py --help.
usage: vexa-preflight [-h] --namespace NAMESPACE [--manifests MANIFESTS] [--snapshot SNAPSHOT]
[--dump-snapshot DUMP_SNAPSHOT] [--kubeconfig KUBECONFIG]
[--context CONTEXT] [--bot-profile {default,none}] [--live-probes]
[--registry-host REGISTRY_HOST] [--pull-test-image PULL_TEST_IMAGE]
[--pull-timeout PULL_TIMEOUT] [--probe-image PROBE_IMAGE] [--json]
vexa-preflight — cluster conformance preflight for a private channel.
Answers, BEFORE first sync and on every upgrade, in plain language: will this
cluster run what the channel delivers? Every check is anchored to a failure
observed in the field — clusters carry taints, LimitRanges and admission
policies we do not control, and the first sync is the wrong moment to learn
that.
Checks
P1 taints-tolerations every delivered workload can schedule on ≥1 node
(anchor: addon pods stranded 6h by a cluster-wide
custom taint; Argo's own pods Pending on tainted
nodes)
P2 limitranges every container declares requests+limits, and the
declared values fit the namespace LimitRange
(anchor: a LimitRange squeezed undeclared bot pods to
64Mi; sizing env vars were dead code for a month)
P3 resourcequota quota headroom covers the declared sums
P4 pod-security OpenShift SCC restricted-v2: explicit UIDs/fsGroups
outside the namespace range are REJECTED (mutation
fixes the rest); PSA restricted: runAsNonRoot,
seccomp, drop-ALL required (anchor: an OpenShift
readiness review — the hardened workloads are exactly
the SCC-rejected ones)
P5 networkpolicy default-deny detection, DNS egress, registry
reachability (static + optional live probe)
P6 shm the bot's 2Gi Memory-medium /dev/shm counts against
its memory limit; LimitRange max and node allocatable
must fit it (anchor: 2Gi shm against a 2560Mi limit is
production's actual configuration)
P7 image-pull the cluster can actually pull a release image by
digest with the namespace's pull secrets (anchor:
images "pulled" only because nodes had them cached;
a real install fails here)
P8 storage a default StorageClass exists if the manifests carry
PVCs
P9 kubernetes version sanity floor
Modes
live (default) reads the cluster via kubectl; --live-probes adds
the in-cluster probe pods (P5 live, P7)
--snapshot FILE air-gapped: read a snapshot produced by
--dump-snapshot on a connected workstation
Workloads under test come from --manifests (rendered YAML; converted via
`kubectl create --dry-run=client -o json`, so kubectl is the only dependency)
plus the built-in dynamic-bot profile (bots are spawned per meeting and never
appear in a chart render; sizes are the measured production values,
overridable). Exit 0 = no FAIL; 1 = at least one FAIL; 2 = usage error.
options:
-h, --help show this help message and exit
--namespace NAMESPACE
target namespace for the delivered workloads
--manifests MANIFESTS
rendered manifests (file or dir) of the delivered set
--snapshot SNAPSHOT read cluster state from a snapshot file (air-gapped mode)
--dump-snapshot DUMP_SNAPSHOT
write the live cluster snapshot to a file and exit
--kubeconfig KUBECONFIG
--context CONTEXT
--bot-profile {default,none}
include the dynamic bot pod profile (absent from renders) in the checks
--live-probes run in-cluster probe pods (DNS/registry, image pull)
--registry-host REGISTRY_HOST
channel registry host[:port] for the reachability probe
--pull-test-image PULL_TEST_IMAGE
image ref (by digest) for the pull probe
--pull-timeout PULL_TIMEOUT
--probe-image PROBE_IMAGE
--json