> For the complete documentation index, see [llms.txt](https://docs.kangal.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.kangal.dev/configuration-and-automation/kangalctl.md).

# kangalctl

`scripts/kangalctl.py` is a source-distributed operator CLI for Admin API contexts, configuration workflows, status checks, and resource CRUD. It is not an independently versioned binary or Python package. Obtain it from the exact Kangal release tag that matches the control plane you operate, and keep the script with the rest of that tag's source tree.

## Runtime and compatibility

From the matching release checkout, create a dedicated environment and install that tag's pinned dependencies:

```bash
git describe --tags --exact-match
python3.12 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
python scripts/kangalctl.py --help
```

This release supports Python 3.11, 3.12, and 3.13. For another release, use the Python versions and dependency pins documented by that tag. The CLI imports Kangal's configuration schemas, validators, and YAML support from the source tree, so copying only `scripts/kangalctl.py` or installing unpinned dependencies is unsupported.

Use the CLI tag that exactly matches the server release. Sharing the `/api/v1` prefix does not guarantee that a CLI from a different release has compatible commands, payload schemas, validation behavior, or response handling. Upgrade the server and CLI as one compatibility unit, then rerun `validate`, server-side dry-run, and a read-only status check before applying changes.

Global options must appear before the command:

```bash
python scripts/kangalctl.py \
  --api-url https://kangal.example.com \
  --token "$KANGAL_TOKEN" \
  status
```

The global options are `--api-url`, `--token`, and `--context`.

## Context file and credentials

Contexts are stored in `~/.kangalctl/config.json` by default. Override the path with `KANGALCTL_CONFIG`, which is useful for CI and isolated operator profiles.

```bash
export KANGALCTL_CONFIG="$HOME/.config/kangal/production.json"
mkdir -p "$(dirname "$KANGALCTL_CONFIG")"
umask 077
```

The CLI stores the bearer token in plaintext in this file. Context display/list redacts it, but the file itself remains sensitive. Restrict permissions, do not commit it, and prefer a short-lived injected file in CI.

Create a context with an existing Admin API token:

```bash
python scripts/kangalctl.py login \
  --context-name production \
  --api-url https://kangal.example.com \
  --token "$KANGAL_TOKEN" \
  --tenant-id tenant-acme
chmod 600 "$KANGALCTL_CONFIG"
```

Or authenticate with a username/password user session:

```bash
python scripts/kangalctl.py login \
  --context-name production \
  --api-url https://kangal.example.com \
  --username admin@example.com \
  --password 'REDACTED' \
  --tenant-id tenant-acme
```

The second form calls `POST /auth/login`. The context name defaults to `default`, and a successful login makes it current unless disabled by the command option.

Manage contexts:

```bash
python scripts/kangalctl.py context list
python scripts/kangalctl.py context show production
python scripts/kangalctl.py context use production
python scripts/kangalctl.py context delete staging
```

## Status

```bash
python scripts/kangalctl.py status
```

Status checks `/health` and `/ready`; when the context or command supplies `tenant_id`, it also attempts to list gateways. Individual unavailable blocks are reported in the output, so inspect every section rather than relying only on process exit status.

## Local validation

Validation is local and does not require an API context:

```bash
python scripts/kangalctl.py validate config/tenant-acme.yaml
python scripts/kangalctl.py validate config/tenant-acme.yaml --strict
```

Strict mode turns missing route-to-service and route/service-to-upstream references within the bundle into errors. It does not validate every resource field or resolve references from live state. Local validation is useful for fast feedback, but server-side validation/dry-run remains required before apply because the server owns the deployed contract and live state.

## Export and diff

```bash
python scripts/kangalctl.py export \
  --tenant-id tenant-acme \
  --format yaml \
  --output backups/tenant-acme.yaml

python scripts/kangalctl.py diff desired/tenant-acme.yaml \
  --tenant-id tenant-acme \
  --strict
```

When `--current` is omitted, `diff` calls the Admin API against live state. To compare two local files:

```bash
python scripts/kangalctl.py diff desired/tenant-acme.yaml \
  --current backups/tenant-acme.yaml \
  --strict
```

YAML is inferred from `.yaml`/`.yml` output extensions, or selected explicitly with `--format`.

## Import and sync

Direct import applies by default. Add `--dry-run` for a preview:

```bash
python scripts/kangalctl.py import desired/tenant-acme.yaml --dry-run
python scripts/kangalctl.py import desired/tenant-acme.yaml --overwrite --dry-run

# Apply only after reviewing the preview.
python scripts/kangalctl.py import desired/tenant-acme.yaml --overwrite
```

Sync has safer CLI defaults: it is dry-run unless `--apply` is supplied, with overwrite, strict validation, and pre-apply snapshot enabled.

```bash
# Preview
python scripts/kangalctl.py sync desired/tenant-acme.yaml \
  --tenant-id tenant-acme \
  --snapshot-note 'release 2026.07.17' \
  --created-by 'change-1842'

# Apply the reviewed plan
python scripts/kangalctl.py sync desired/tenant-acme.yaml \
  --tenant-id tenant-acme \
  --apply \
  --snapshot-note 'release 2026.07.17' \
  --created-by 'change-1842'
```

Overrides are available when intentional:

* `--no-overwrite` skips matching live resources.
* `--no-snapshot` disables the pre-apply snapshot.
* `--strict` / `--no-strict` selects reference validation.

Prefer sync for managed promotion because the single operation returns validation, live diff, counts, and snapshot information. Remember that neither import nor sync prunes resources omitted from a bundle.

## Resource CRUD

Supported entity names are:

```
gateways, services, routes, upstreams, targets,
certificates, ca-certificates, snis, vaults, redis-configs,
data-planes, consumers, consumer-groups, consumer-credentials,
realms, api-tokens
```

Singular aliases are accepted. Inspect exact command options with help:

```bash
python scripts/kangalctl.py get --help
python scripts/kangalctl.py create --help
python scripts/kangalctl.py update --help
python scripts/kangalctl.py delete --help
```

List resources:

```bash
python scripts/kangalctl.py get gateways \
  --tenant-id tenant-acme

python scripts/kangalctl.py get services \
  --tenant-id tenant-acme \
  --gateway-id gw-production \
  --label-selector 'environment=production' \
  --limit 100 \
  --offset 0 \
  --sort name \
  --order asc

python scripts/kangalctl.py get targets \
  --tenant-id tenant-acme \
  --gateway-id gw-production \
  --upstream-id orders-upstream
```

Gateway-scoped entities require `--gateway-id`; target listing also requires `--upstream-id`. Other filters include tenant, consumer, label selector, limit, offset, sort, and order. The CLI forwards supplied filters, while each Admin API endpoint defines which ones it applies.

Create, update, and delete:

```bash
python scripts/kangalctl.py create services \
  --gateway-id gw-production \
  --file service.yaml

python scripts/kangalctl.py update services service-id \
  --gateway-id gw-production \
  --file service-update.yaml

python scripts/kangalctl.py delete services service-id \
  --gateway-id gw-production
```

Input files may be JSON or YAML; suffix determines parsing. CRUD permissions follow HTTP method: reads need `admin:read`, writes need `admin:write`.

## SDK artifact export

Download a generated SDK for a published portal API version:

```bash
mkdir -p artifacts
python scripts/kangalctl.py sdk export \
  --service-id SERVICE_ID \
  --version-id VERSION_ID \
  --tenant-id tenant-acme \
  --gateway-id gw-production \
  --target python \
  --output artifacts/orders-python.zip
```

Targets are `typescript-fetch`, `python`, `go`, `java`, `csharp`, and `php`. The CLI validates the returned Base64 payload, media type, declared size, SHA-256 checksum, and output filename. It refuses to replace an existing artifact unless `--force` is supplied, and the destination directory must already exist.

## Automation pattern

Use an isolated context file and fail the pipeline before apply when validation or preview fails:

```bash
set -euo pipefail

export KANGALCTL_CONFIG="$RUNNER_TEMP/kangalctl.json"
python scripts/kangalctl.py login \
  --context-name ci \
  --api-url "$KANGAL_URL" \
  --token "$KANGAL_TOKEN" \
  --tenant-id "$TENANT_ID"
chmod 600 "$KANGALCTL_CONFIG"

python scripts/kangalctl.py validate desired.yaml --strict
python scripts/kangalctl.py sync desired.yaml --tenant-id "$TENANT_ID"

# Put this behind the deployment environment's approval gate.
python scripts/kangalctl.py sync desired.yaml \
  --tenant-id "$TENANT_ID" \
  --apply \
  --snapshot-note "$RELEASE_REF" \
  --created-by "$CI_ACTOR"
```

The HTTP client timeout is 30 seconds. Large exports/imports or an overloaded API can exceed it; reduce bundle size, check API/database health, and retry only after determining whether a write partially completed.

## Snapshot operations

Use the Admin API calls in [Import, export, and rollback](/configuration-and-automation/import-export-rollback.md) to create, list, preview, and apply configuration snapshots. Continue to use `kangalctl` for validation, live diff, import, and sync around that snapshot workflow.

## Troubleshooting

| Symptom                                | Resolution                                                                                                                                               |
| -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `No active context`                    | Run `login` or `context use`, or pass global `--api-url` and `--token` before the command.                                                               |
| Global option is rejected              | Move `--api-url`, `--token`, or `--context` before the subcommand.                                                                                       |
| Context works locally but not in CI    | Set `KANGALCTL_CONFIG` explicitly and create/login within the job.                                                                                       |
| `401`                                  | Token is missing, expired, revoked, or for another environment. Login again or rotate the Admin API token.                                               |
| `403` on write                         | Use a writer/admin role and an Admin API token with `admin:write`; verify tenant permissions.                                                            |
| CLI and server behavior differ         | Confirm that `git describe --tags --exact-match` reports the exact server release tag, then recreate the environment from that tag's `requirements.txt`. |
| Import fails before making a request   | Use a Python version supported by the selected tag and reinstall its pinned dependencies; do not run a copied standalone script.                         |
| Request times out                      | Check `/health`, `/ready`, API logs, MongoDB, and bundle size. A timed-out write may have partially applied.                                             |
| Import changed live state unexpectedly | Direct import applies unless `--dry-run`; export and diff immediately, then choose a forward fix or tested rollback.                                     |
| Output file contains redacted secrets  | Expected. Do not use it as a secret backup or overwrite secrets with placeholders.                                                                       |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.kangal.dev/configuration-and-automation/kangalctl.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
