> ## Documentation Index
> Fetch the complete documentation index at: https://delivery.vexa.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# vexa_preflight.py

> Will this cluster run what the channel delivers?

Source: `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 from `python3 kit/preflight/vexa_preflight.py --help`.

```text theme={null}
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
```
