Skip to content

Latest commit

 

History

History
108 lines (86 loc) · 4.78 KB

File metadata and controls

108 lines (86 loc) · 4.78 KB

Agent guide

This file is for AI agents (and scripts) that need to set up or drive kexplain for a user. Everything here is non-interactive and machine-checkable.

What this tool is

kexplain explains Karpenter provisioning decisions: which pods triggered a node, which constraints narrowed the choice, what EC2 CreateFleet picked and why, and what disruption removed it. Single-file Python 3.8+, stdlib only, no dependencies to install.

Setup for a user, step by step

# 1. install (any dir on PATH)
pipx install git+https://github.com/inceptionstack/karpenter-explain
# or: pip install --user git+https://github.com/inceptionstack/karpenter-explain
# or copy the single file: cp kexplain.py ~/.local/bin/kexplain && chmod +x ~/.local/bin/kexplain

# 2. point kubectl at the user's cluster
aws eks update-kubeconfig --name <cluster> --region <region>

# 3. verify everything, machine-readable
kexplain doctor --json

doctor --json prints {"ok": true|false, "checks": [...]} where each check has check, ok, detail, and (on failure) fix with the exact remediation. Exit code 0 means ready, 3 means something required is broken. The checks aws ec2 access and debug logging are optional: ok stays true without them, but prices/funnel/plan/why-not need the former and candidate lists need the latter.

If doctor says karpenter runs in a nonstandard namespace, set KARPENTER_NAMESPACE=<ns>. If the store path is not writable, set KEXPLAIN_STORE=<dir>.

Every regular command runs a fast preflight first and falls through to doctor output automatically when the basics are broken, so you will never get a raw stack trace for a missing kubeconfig.

Driving it non-interactively

Do NOT use kexplain wizard (it requires a TTY and will exit immediately for you). Use the direct commands:

Task Command
health check kexplain doctor --json
harvest state (cron this for history retention) kexplain sync
list nodes incl. deleted ones kexplain nodes --json
decision timeline kexplain history --json --since 24
full trace for a node kexplain --no-color explain <target> --json
why type X was rejected kexplain --no-color explain <target> --why-not <type>
simulate a deployment kexplain --no-color plan -f <file>

<target> accepts a node name, nodeclaim name, EC2 instance id, or any unique prefix.

doctor, nodes, history, and explain all support --json; prefer it when parsing. explain --json returns the full story object (timestamps, trigger pods with scheduling reasons, candidates, disruption). plan is text only. For human-facing text, pass --no-color.

Exit codes: 0 success, 1 error (bad target, unparseable file), 3 doctor found required checks failing.

Data and side effects

  • Reads: kubectl (logs, pods, nodes, nodeclaims, nodepools, events), and two read-only AWS calls (ec2:DescribeInstanceTypes, ec2:DescribeSpotPriceHistory). It never mutates cluster or AWS state.
  • Writes: only ~/.kexplain/<cluster>/ (or KEXPLAIN_STORE). This store contains node names, private IPs, and instance ids. Do not commit it or send it anywhere.
  • Every command auto-harvests before running; --no-sync skips that when you need speed and the store is fresh.

Provisioning a demo cluster (only if the user asks)

infra/create-cluster.sh creates a real EKS cluster + Karpenter v1.13 in us-east-1 and costs real money (about $0.35/hr idle). Takes ~20 minutes. infra/teardown.sh removes everything. Never run either without the user explicitly asking.

Development

  • Version: __version__ in kexplain.py is the single source of truth (pyproject reads it dynamically). The version-bump GitHub Action sets it to 0.1. on every push to main. Do not bump it by hand.
  • Code lives in the single kexplain.py file, organized by section markers (# --- store, # --- decision model, # --- commands, ...).
  • Tests: python3 -m unittest discover tests. They run offline against fixtures captured from a real Karpenter v1.13 cluster; no cluster or AWS needed. Add a fixture-based test when you change log parsing, the funnel, or requirement matching.
  • Style rules that are hard requirements in this repo: no em-dashes anywhere (docs, comments, output strings), plain direct prose, and commit messages carry no AI attribution of any kind.
  • Before pushing: python3 -m unittest discover tests must pass and grep -rnP '\x{2014}' $(git ls-files) (the em-dash gate) must come back empty. CI enforces both.
  • Local quality gate: enable the pre-commit hook once per clone with git config core.hooksPath .githooks. It runs the syntax check, the unit tests, and the em-dash gate before each commit, so a bad commit is caught locally instead of in CI. It does not touch the version (the Action owns that).