Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions astro.sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,17 @@ const apisAndSdksItems = (prefix: string) => [
`${prefix}/reference/python-client`,
],
},
{
label: 'Extensions',
collapsed: true,
items: [
`${prefix}/reference/extensions/overview`,
`${prefix}/reference/extensions/quickstart`,
`${prefix}/reference/extensions/development-workflow`,
`${prefix}/reference/extensions/cli-deployment`,
`${prefix}/reference/extensions/deployment-api`,
],
},
{
label: 'Mobile',
collapsed: true,
Expand Down
1 change: 1 addition & 0 deletions src/assets/schemas/extension-deployment-options-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/schemas/extension-deployment-options.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/schemas/extension-dev-workflow-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/schemas/extension-dev-workflow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/schemas/extension-lifecycle-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/schemas/extension-lifecycle.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/schemas/extension-mode-private-cloud-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/schemas/extension-mode-private-cloud.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/schemas/extension-mode-public-cloud-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/schemas/extension-mode-public-cloud.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/schemas/extension-mode-self-hosted-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/schemas/extension-mode-self-hosted.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/schemas/extension-request-flow-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/schemas/extension-request-flow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions src/content/_includes/docs/reference/apis-and-sdks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ import DocLink from '@components/DocLink.astro';
- <DocLink product={props.product} path='reference/java-client' bold={false}>Java REST Client</DocLink>
- <DocLink product={props.product} path='reference/python-client' bold={false}>Python REST Client</DocLink>
</ListCard>

<ListCard headingLevel={3} title="Extensions" icon="puzzle">
- <DocLink product={props.product} path='reference/extensions/overview' bold={false}>Overview</DocLink>
- <DocLink product={props.product} path='reference/extensions/quickstart' bold={false}>Quickstart</DocLink>
- <DocLink product={props.product} path='reference/extensions/development-workflow' bold={false}>Development workflow</DocLink>
- <DocLink product={props.product} path='reference/extensions/cli-deployment' bold={false}>Deploy with the CLI</DocLink>
- <DocLink product={props.product} path='reference/extensions/deployment-api' bold={false}>Deployment API</DocLink>
</ListCard>
</CardGrid>

## Mobile apps
Expand Down
189 changes: 189 additions & 0 deletions src/content/_includes/docs/reference/extensions/cli-deployment.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
import { Aside } from '@astrojs/starlight/components';
import DocLink from '@components/DocLink.astro';
import Banner from '~/components/Banner.astro';
import { Products } from '~/models/site.models';

<Banner variant="peFeature" product={props.product}>Extensions work only with <DocLink product={Products.PE} path="reference/extensions/cli-deployment" target="_blank">ThingsBoard Professional</DocLink> and <a href="/installations/?product=thingsboard-cloud" target="_blank" rel="noopener noreferrer" class="tb-banner-ext"><b>ThingsBoard Cloud</b></a> version **4.3.1.3** or later.</Banner>

{props.product !== Products.CE && (
<Banner variant="cloud">Available from ThingsBoard PE/Cloud <strong>4.3.1.3</strong> and later.</Banner>
)}

The <DocLink product={props.product} path='user-guide/cli'>ThingsBoard CLI</DocLink> is the easiest way to run an extension inside ThingsBoard Cloud or PE. This page is the reference for the `tb extension deploy` command and the `tb extension deployments` control commands. For a full walkthrough, see the <DocLink product={props.product} path='reference/extensions/quickstart'>Quickstart</DocLink>.

<Aside type="note">
Deploying is different from the local dev loop (`tb extension build` / `run` / `logs` / `stop`), which runs the container on your own machine. **Deploy** provisions the container **server-side**, and ThingsBoard keeps it running.
</Aside>

## Before you deploy

`deploy` only provisions an image the registry already holds. Push it first:

```bash
tb extension push --image-name myorg/acme-billing
```

When you push a version tag (`--image-tag 1.1.0`), the CLI also pushes the same build as `:latest`, replacing the registry's current `latest`. Pass `--no-latest` to skip that — for example, for release candidates.

Authentication uses your active profile. Override it per command with `--profile <name>`, or with `--url` and `--api-key`. The profile also decides **where** the extension runs — ThingsBoard Cloud or your own PE installation (see <DocLink product={props.product} path='reference/extensions/overview#where-extensions-run'>Where extensions run</DocLink>).

The registry must be reachable from the ThingsBoard instance that pulls the image: the public internet for ThingsBoard Cloud, or your own network for a private PE installation. For a private registry, ThingsBoard needs pull credentials — pass them with the registry flags of `deploy` (see [Private registry](#private-registry)).

## Commands at a glance

| Command | What it does |
|---------|--------------|
| `tb extension deploy` | Create or update the deployment from a pushed image |
| `tb extension undeploy [ref]` | Tear down the deployment and its entity |
| `tb extension sizes` | List the available resource sizes |
| `tb extension deployments list` | List this tenant's deployed extensions |
| `tb extension deployments status <ref>` | Show live state, replicas, and URL |
| `tb extension deployments logs <ref>` | Tail the container logs |
| `tb extension deployments restart <ref>` | Roll out a restart |
| `tb extension deployments stop <ref>` | Scale to zero (keep the entity) |
| `tb extension deployments start <ref>` | Resume to the desired replicas |

`<ref>` is the extension **slug** or **UUID**. When a flag is omitted, the CLI reads its value (name, image, slug, size) from the project's `thingsboard.json`.

## `tb extension deploy`

Create or update the deployment. The CLI shows a confirmation panel, sends the request, and by default waits until the extension is `ACTIVE`.

```bash
tb extension deploy --image-name myorg/acme-billing --image-tag 1.0 --replicas 2 --size medium
```

```text
╭─ tb extension deploy ─────────────────────────────╮
│ Deploy 'acme-billing' │
│ image: myorg/acme-billing:1.0 │
│ replicas: 2 port: 8090 │
│ size: medium │
│ target: https://thingsboard.cloud │
╰────────────────────────────────────────────────────╯
Proceed? [y/N]: y
OK Deployed 'acme-billing' → acme-billing-9f3a (2/2 replicas ready)
URL: https://thingsboard.cloud/api/ext/acme-billing-9f3a
```

### Flags

| Flag | Default | Description |
|------|---------|-------------|
| `--image-name` | saved image | Registry image repository, **without a tag** |
| `--image-tag` | `latest` | Image tag |
| `--name` | saved extension name | Human-readable extension name (from `thingsboard.json`, set by `tb extension new` or `rename`) |
| `--slug-base` | from name | Base for the generated slug |
| `--replicas` | `1` | Number of replicas (1–20) |
| `--port` | `8090` | Port the container listens on |
| `--env KEY=VALUE` | — | Environment variable; repeat for more than one. Names starting with `TB_EXT_`, and the key `THINGSBOARD_URL`, are reserved |
| `--size` | `small` | Resource size — run `tb extension sizes` to list the options |
| `--registry` | from image | Private registry host. When omitted, ThingsBoard derives it from the image reference |
| `--registry-user` | — | Username (or robot account) for a private registry — see [Private registry](#private-registry) |
| `--registry-password-secret` | — | Name of a ThingsBoard Secret that holds the registry password — see [Private registry](#private-registry) |
| `--clear-registry-auth` | — | On an update, remove the stored registry credentials instead of keeping them |
| `--clear-env` | — | On an update, remove all environment variables instead of keeping them |
| `--wait` / `--no-wait` | `--wait` | Wait until `ACTIVE`/`FAILED`, or return at once |
| `--timeout` | `180` | Wait timeout, in seconds |
| `-y` / `--yes` | — | Skip the confirmation prompt |

<Aside type="caution">
`--image-name` must not include a tag. Pass the tag with `--image-tag`. A registry host and port (`registry.example.com:5000/team/foo`) is fine — only a real `:tag` is rejected.
</Aside>

The `size:` line is always shown — it takes its value from `--size`, the saved deployment, or the default. Optional flags you set add extra rows. For example, `--env LOG_LEVEL=debug --size medium` shows:

```text
│ size: medium │
│ env: LOG_LEVEL=debug │
```

On an update, when you do not pass `--env` or the registry flags, the CLI keeps the current values from the server. The panel then shows `env: (kept from current deployment)` or `registry-auth: (kept from current deployment)`.

With `--no-wait`, the command returns immediately and the state updates in the background:

```text
OK Provisioned 'acme-billing' → acme-billing-9f3a (state will converge; use deployments status)
```

### Private registry

ThingsBoard pulls the image on the server side, so it needs its own pull credentials — your local `docker login` does not help here. The CLI never sends the password itself. Instead, it sends a reference to a ThingsBoard Secret:

1. Create a Secret with the registry password under your tenant — use the **Secrets** page in the ThingsBoard UI, or `POST /api/secret`.
2. Deploy with the username and the secret name:

```bash
tb extension deploy --registry-user robot-acme --registry-password-secret acme-registry
```

`--registry-user` and `--registry-password-secret` are required together. `--registry` is optional: when omitted, ThingsBoard takes the registry host from the image reference. Under the hood, the CLI fills the `registryAuth` field of the <DocLink product={props.product} path='reference/extensions/deployment-api'>deployment API</DocLink> and sends the password as a `${secret:acme-registry;type:TEXT}` reference. You can also pass a full `${secret:…}` reference as the flag value — the CLI keeps it as is.

You set the registry flags once. On later updates, the CLI keeps the credentials from the current deployment — you do not repeat the flags. Pass new values to replace them, or `--clear-registry-auth` to remove them.

## Resource sizes

Run `tb extension sizes` to list the resource tiers and the CPU and memory each one maps to. Pass the chosen tier to `deploy` with `--size` (for example `xsmall`, `small`, `medium`, `large`). Start small and move up only if the extension needs more.

## `tb extension undeploy [ref]`

Delete the deployment and its entity. With no `ref`, the CLI uses the saved deployment from `thingsboard.json`.

```bash
tb extension undeploy acme-billing-9f3a
```

## Inspecting and controlling a deployment

```bash
tb extension deployments list # all extensions in the tenant
tb extension deployments status acme-billing-9f3a # live state, replicas, URL
tb extension deployments logs acme-billing-9f3a -n 200 # tail the last 200 log lines
tb extension deployments restart acme-billing-9f3a # roll out a restart
tb extension deployments stop acme-billing-9f3a # scale to zero, keep the entity
tb extension deployments start acme-billing-9f3a # resume to the desired replicas
```

`list` prints one row per extension: name, slug, state, resource size, image, and the Swagger path.

`status` shows the live state, ready and desired replicas, the public URL, and the Swagger path. It adds a **Last error** row only when the extension reports one.

## Deployment state in the project

After a successful deploy, the CLI saves the deployment details in the project's `thingsboard.json`:

```json
{
"extension": {
"name": "acme-billing",
"language": "java",
"deployment": {
"id": "…", "slug": "acme-billing-9f3a",
"lastImage": "myorg/acme-billing", "lastTag": "1.0", "size": "medium"
}
}
}
```

Because of this, a later `tb extension deploy` with no flags **updates** the same extension using the saved image, slug, and size — you do not have to repeat them. The environment variables and the private-registry credentials are also kept on an update: the CLI copies them from the current deployment on the server. Pass `--env` or the registry flags to replace them, or `--clear-env` / `--clear-registry-auth` to remove them. Note that `--env` replaces the whole set — repeat every variable you want to keep. Only the image tag is **not** reused: `lastTag` is informational, and without `--image-tag` the CLI deploys `latest`. So pass `--image-tag` on every update.

## Deploy from CI

Environment variables let you deploy without an interactive profile — useful in a pipeline:

```bash
export TB_URL=https://thingsboard.cloud
export TB_API_KEY=tb_XXXX
tb extension deploy --image-name myorg/acme-billing --image-tag "$CI_COMMIT_TAG" -y --no-wait
```

`TB_URL` sets the instance, `TB_API_KEY` supplies the key, `-y` skips the prompt, and `--no-wait` returns at once.

<Aside type="note">
These two variables configure the **CLI**. They are not the same as `TB_AUTH_API_KEY`, which is a runtime credential **inside the extension container** — see the <DocLink product={props.product} path='reference/extensions/overview'>overview</DocLink>.
</Aside>

## Next steps

- <DocLink product={props.product} path='reference/extensions/deployment-api'>Deployment REST API</DocLink> — the endpoints the CLI calls, for use without the CLI.
- <DocLink product={props.product} path='reference/extensions/quickstart'>Quickstart</DocLink> — the full build-and-deploy walkthrough.
Loading