# `tare uninstall`

> Reference for tare uninstall, which tears down the Agent Router data plane from a Kubernetes cluster.

# `tare uninstall`

  Tear down the Agent Router dataplane from a Kubernetes cluster.

## Synopsis

```
tare uninstall <identity-file> [flags]
```

## Description

`tare uninstall` reverses `tare install` in a single command. After a successful
run, the Helm release is gone, the `tars-system` and `tars-dataplane` namespaces
have been removed, and the CRDs the install brought have been deleted.

This is **mostly a cluster-only operation**, with one management-plane side
channel: after `helm uninstall` runs (phase 2), the CLI reports the uninstall
event to MP so the workspace's deployment history reflects it. See
[Management-plane event reporting](#management-plane-event-reporting) below.

`tare uninstall` does not:

- Deregister the dataplane URL from your workspace.
- Revoke the service-account identity.
- Touch the management-plane database directly (beyond the install-event side
  channel, which is bounded to the `dataplane_install_events` table).

If you need to clean up the dataplane URL registration or the SA identity, use
the dashboard or the `tars sa` command.

`helm` and `kubectl` are downloaded automatically on first run into
`~/.tare/tools/` if they are not already on PATH.

## Phases

```
[1/6] Preflight (Helm 3+, kubectl, cluster)
[2/6] helm uninstall <release> -n <system-namespace>
      └── after helm uninstall: sync-POST uninstall event to MP
          (CM fallback on 5xx; see "Management-plane event reporting" below)
[3/6] Patch finalizers in tars-system / tars-dataplane + delete GatewayClass tars-egress
[4/6] Delete namespaces (system, dataplane)
[5/6] Wait for namespaces to disappear
[6/6] Delete TARS-owned CRDs (skipped under the multi-DP guard; see --force)
```

Phase ordering is deliberate:

- **Phase 3 runs before phase 4** so the namespace delete in phase 4 has no
  blockers. We enumerate the namespaced resource kinds in the chart's API
  groups (`aigateway.envoyproxy.io`, `tars.tetrate.ai`, `gateway.networking.k8s.io`,
  `gateway.envoyproxy.io`), list any in both `tars-system` and
  `tars-dataplane` that carry finalizers, and patch `metadata.finalizers: []`
  on them. Both namespaces are covered: `tars-system` holds the bulk of the
  chart's CRs and controllers, but `tars-dataplane` can also hold
  finalizer-bearing resources such as `EnvoyPatchPolicy`.
- **Phase 4 deletes the namespaces** which sweeps every namespaced resource
  in one stroke. Immediately after issuing each delete, we clear the
  namespace's `.spec.finalizers` via the `/finalize` subresource: the
  standard "force a stuck namespace through" technique. Safe here because
  we have already patched all resource finalizers and the goal of the
  command is to tear the namespaces down.
- **Phase 5 polls** for the namespaces to disappear.
- **Phase 6 deletes CRDs**, by which point no CRs of any owned kind exist,
  so CRD deletion has nothing left to wait on.

## Examples

```bash
# Standard teardown with confirmation prompt.
tare uninstall identity.json

# Non-interactive (CI).
tare uninstall identity.json --yes

# Stuck finalizers: bypass controller cleanup and patch them empty.
tare uninstall identity.json --yes --force

# Multi-DP cluster: leave CRDs in place so other releases keep working.
tare uninstall identity.json --yes --keep-crds

# Preview without touching the cluster.
tare uninstall identity.json --dry-run
```

## Flags

| Flag | Default | Description |
|---|---|---|
| `--keep-crds` | false | Leave CRDs in place. Use on shared / multi-DP clusters. |
| `--force` | false | Override the multi-DP guard and delete CRDs even when other releases share them. |
| `--yes` | false | Skip the typed-confirmation prompt. |
| `--timeout` | `5m` | Per-phase wait timeout. |
| `--dry-run` | false | Print the plan and run `helm uninstall --dry-run`; no cluster mutation. |
| `--skip-preflight` (hidden) | false | Skip Helm/kubectl/cluster preflight (also `TARE_SKIP_PREFLIGHT=1`). |
| `--release-name` (hidden) | `tars` | Helm release name. |
| `--system-namespace` (hidden) | `tars-system` | Kubernetes system namespace. |
| `--dataplane-namespace` (hidden) | `tars-dataplane` | Kubernetes dataplane namespace. |

Inherited from root: `--verbose`, `--quiet`.

## What gets deleted

Namespaced resources (cleared via the namespace delete in phase 4):

- All objects in `tars-system` and `tars-dataplane`, including the image-pull
  secret created by `tare install --image-pull-secret-stdin`.

Cluster-scoped resources (explicit deletes):

- `GatewayClass/tars-egress`
- CRDs in groups `aigateway.envoyproxy.io` and `tars.tetrate.ai`

## What is preserved

- CRDs in `gateway.networking.k8s.io` (commonly centrally managed; GKE, distro
  bundles, etc.).
- CRDs in `gateway.envoyproxy.io` (Envoy Gateway distribution, often shared).
- Any namespaces, secrets, or ConfigMaps outside `tars-system` and
  `tars-dataplane` that an operator created independently.
- Management-plane state, except for the single new row appended to
  `dataplane_install_events` (one row per uninstall, see
  [Management-plane event reporting](#management-plane-event-reporting)).

## Management-plane event reporting

Between phase [2/6] (`helm uninstall`) and phase [3/6] (finalizer sweep),
`tare uninstall` reports the operation to the management plane:

1. Read the pre-uninstall Helm revision (`preRev`) so the event payload can
   carry the `helm_revision` that matches the install / upgrade events in the
   workspace's deployment history. The PK is unrecoverable once `helm uninstall`
   has run, which is why the read happens before phase 2.
2. After `helm uninstall` returns, sync-POST the event to
   `POST /v1/dataplane-install-events` on the management plane, signed with
   the identity file's SA token.
3. On `2xx`: bump the `tars-doctor-install-event-state` ConfigMap so the
   doctor's reconciler doesn't re-emit a synthetic event on its next tick,
   then continue with phases 3–6.
4. On `5xx` or network failure: write a ConfigMap to `tars-system` labelled
   `tars.io/component=install-event`, same shape as the install / upgrade
   outbox CMs. The `tare-doctor` cron in that cluster would normally pick it
   up on the next tick, **but** the namespace is about to be deleted in
   phase 4, so the CM may not survive long enough to be forwarded. This is
   a known limitation: the dashboard timeline may not show
   an `uninstall` row in this failure case.
5. On `4xx`: log a warning and skip the fallback (the next retry would
   re-reject with the same error). The CLI continues teardown.

The event POST **never blocks teardown, never changes the CLI's exit code,
and never re-prompts**. The dataplane is removed regardless of whether the
management plane could be reached.

Configured via the identity file's `apiUri`. No env var override is honored
on this code path (the doctor's `TARE_DOCTOR_API_URI` only affects in-cluster
forwarding, not CLI-side uninstall reporting).

## Confirmation prompt

By default `tare uninstall` prints the plan and asks the operator to type the
system namespace name to confirm. Use `--yes` to skip in automation.

```
About to uninstall Agent Router dataplane:

  Identity:          identity.json  (client_email: tetrate@example.sa.iam.tetrate.ai)
  Release:           tars
  System namespace:  tars-system
  Dataplane:         tars-dataplane
  CRDs:              will be deleted (aigateway.envoyproxy.io, tars.tetrate.ai)

  Touches MP: appends one row to dataplane_install_events (operation=uninstall) after helm uninstall.
  NOT touched: dataplane URL registration, SA identity revocation, image-pull secrets outside the namespaces above.

Type the system namespace name (tars-system) to confirm: _
```

## Stuck finalizers

The Agent Router CRs (`AIGatewayRoute`, `MCPRoute`, `BackendSecurityPolicy`, etc.)
and `GatewayClass/tars-egress` carry finalizers that the dataplane
controllers normally clear during a graceful delete. After phase 2's
`helm uninstall` removes those controllers, the finalizers can never clear
on their own: the only reconciler that could is gone.

For this reason, `tare uninstall` automatically patches `metadata.finalizers: []`
on any CR or `GatewayClass` that remains after a brief poll. This is the
only path to completion at that point and does not require `--force`.

The patch bypasses controller cleanup hooks (egress backends may remain
registered with external services, telemetry exports may not be flushed).
That is the unavoidable cost of teardown; the same cost applies whether
you patch via `tare uninstall` or via `kubectl patch` by hand.

## Multi-DP guard

Before deleting CRDs in phase 6, `tare uninstall` runs `helm list -A` and
checks for other releases of the same chart. Behaviour:

| Situation | Effect |
|---|---|
| No other Agent Router releases | CRDs are deleted. |
| Other releases found, `--force` not set | CRDs **skipped**. Other releases remain functional. Command exits 0 with a warning. |
| Other releases found, `--force` set | CRDs deleted anyway. Other releases will break. |
| `--keep-crds` set | Phase 6 skipped unconditionally. No detection run. |

## Dry run

`--dry-run` prints the plan, runs `helm uninstall --dry-run`, lists the CRs
that would be drained, lists the CRDs that would be deleted (or notes the
multi-DP skip), and names the namespaces that would be removed. No mutating
calls (`kubectl delete`, `kubectl patch`, `helm uninstall` without `--dry-run`)
are made.

## Exit codes

- `0`: Success, or "nothing to do" (release already absent).
- `1`: Phase failed; see error message.

Where to go next

  <Link to="/reference/tare-cli/install" className="tare-nav-card">
    tare install
    Install the dataplane that this command tears down.
  </Link>
  <Link to="/reference/tare-cli/upgrade" className="tare-nav-card">
    tare upgrade
    Move an installed dataplane to a newer version instead of reinstalling.
  </Link>
