Skip to content
Merged
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
4 changes: 2 additions & 2 deletions src/content/docs/admin/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ module "spin" {
}
```

When the control plane starts, it creates each item of the file that the installation does not
have yet: a setting, a preset, a network policy. From then on, the dashboard is where they change.
When the control plane starts, [it creates each item of the file that the installation does not
have yet](<feature:Installation settings seeded from a file; a change in the file is a proposal to apply or dismiss>): a setting, a preset, a network policy. From then on, the dashboard is where they change.

When the file later says something different about an item, the control plane does **not** write
over what an administrator decided. It records the difference as a **proposal**, and the dashboard
Expand Down
7 changes: 4 additions & 3 deletions src/content/docs/admin/hosts.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ reads:

import Value from '../../../components/Value.astro';

Runners are also called **hosts**. An administrator manages them in **Admin → Runners** or with
`spin admin runner`. For how runners join, scale and go away, see
Runners are also called **hosts**. [An administrator manages them in **Admin → Runners** or with
`spin admin runner`](<feature:Runners: registration tokens, drain, activate, revoke, and a policy per host>). For how runners join, scale and go away, see
[Runners and hosts](/concepts/runners/).

## Seeing them
Expand All @@ -20,7 +20,8 @@ spin admin runner list
spin admin versions # the control plane's release, and each runner's and its machine's
```

A runner's page in the dashboard shows its state, its capacity and its workspaces.
`spin admin versions` says [what is running where](<feature:What is running where: the control plane, each runner and its machine>). A runner's page in the dashboard shows its
state, its capacity and its workspaces.

## Drain and activate

Expand Down
6 changes: 3 additions & 3 deletions src/content/docs/admin/observability.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,16 @@ stops, so a machine replaced by an update takes nothing with it.
| Traces | 7 days |
| Metrics | 30 days |

Retention and whether workspaces' console output is collected are
Retention and [whether workspaces' console output is collected](<feature:A workspace's journal and console are collected as the installation's policy says>) are
[installation settings](/admin/configuration/).

## Reading them

| Where | What |
|---|---|
| **Admin → Logs** | Search the control plane's, the proxy's and the runners' logs |
| **Admin → Logs** | [Search the control plane's, the proxy's and the runners' logs](<feature:Platform logs, workspace logs and traces, searched in the product>) |
| **Admin → Traces** | Find a trace, such as one workspace's start from the request to the guest (`span_name:workspace.start`) |
| **Admin → Metrics** | Grafana, over the metric store, inside the dashboard |
| **Admin → Metrics** | [Grafana, over the metric store, inside the dashboard](<feature:Metrics, with Grafana on the control plane>) |
| A workspace's **Logs** tab | What its machine printed |
| `spin admin logs` | The same search as Admin → Logs, from the CLI |
| `spin workspace logs <name>` | A workspace's console, from the CLI |
Expand Down
134 changes: 134 additions & 0 deletions src/content/docs/admin/operations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
---
title: Jobs, the bill and the store
description: What an administrator runs and reads beyond runners, from the control plane's jobs and the month's bill to the store, disk keys and a root shell.
reads:
- "spin:cmd/cli/cmd/admin_jobs.go@v20261110.01"
- "spin:cmd/cli/cmd/admin_costs.go@v20261110.01"
- "spin:cmd/cli/cmd/admin_storage.go@v20261110.01"
- "spin:cmd/cli/cmd/admin_volume.go@v20261110.01"
- "spin:cmd/cli/cmd/admin_shell.go@v20261110.01"
---

These are the `spin admin` commands that are not about a runner's state. For drain, activate and
revoke, see [Operating hosts](/admin/hosts/).

## Jobs

The control plane does periodic work as jobs. You can
[list the jobs and run one now](<feature:The control plane's jobs, and running one now>).

```bash
spin admin jobs list
spin admin jobs run <job>
```

The list says how often each job runs and how its last run went. `run` does not wait for the job:
read the list again to see how it went. A job that is already running is refused.

## The bill

`spin admin costs` shows
[the month's bill, its forecast and each workspace's share](<feature:The month's bill, its forecast, and what each workspace cost>).

```bash
spin admin costs
spin admin costs --month <yyyy-mm>
spin admin costs by workspace
spin admin costs by team
spin admin costs by owner
```

The first form is the cloud's bill by service, what the month is forecast to end at, and its
budget. It is the bill as the control plane last read it, never the cloud itself. The control
plane reads only the costs that `bill_scope` names in the
[configuration file](/reference/configuration/file/): without a scope it reads none.

`by` shares the month out. The runners are shared by the cores and memory each workspace held,
and the volumes' bucket by what its volumes kept. What nobody caused is said apart and never
spread: runner capacity nobody held, bytes no workspace keeps, and the platform's own cost by
service.

## The store

`spin admin storage` shows
[every volume in the store and whose it is, and removes what nothing needs](<feature:The store: every volume, whose it is, and taking out what nothing needs>).

```bash
spin admin storage list
spin admin storage explain <key>
spin admin storage untag-image <ref>
spin admin storage remove <volume-id>
```

`list` says whether each volume may be removed, as the `storage-gc` job last read the store.
`explain` says what a key copied from the bucket's console is, and whose.

`remove` takes out an image, an extension release, an unclaimed volume or an orphan, and destroys
its key. An image its ref still names is untagged first. A workspace's disk, the newest release
of an extension, and a release a workspace runs are refused.

## Re-keying a disk

When a key is assumed taken by a host that held it, you can
[re-key the workspace's disk](<feature:Re-key a workspace's disk>).

```bash
spin admin volume rekey <workspace-id>
spin admin volume rekeys
```

`rekey` copies the disk whole under a key of its own, points the workspace at the copy and deletes
the old disk. That destroys the old key, and every snapshot of the disk with it. The workspace
is anybody's, named by its id, and must be stopped or quarantined. A disk something was cloned from is refused. `rekeys` lists the
disks being re-keyed, and the ones a revoked host's keys marked for it.

## A root shell on a runner

An administrator can open
[a root shell on a runner, for a while and with a reason](<feature:A root shell on a runner, for a while and with a reason: the runner emptied first, every session recorded under Object Lock, the runner retired after>).

```bash
spin admin shell open <runner-id> --reason "<why>" --minutes <minutes>
spin admin shell open <runner-id> --reason "<why>" --incident
spin admin shell list
spin admin shell approve <shell-id>
spin admin shell close <shell-id>
spin admin shell recording <shell-id>
```

The runner is emptied first: each workspace is suspended and resumed on another runner. With
`--incident` the shell opens on the runner as it is. Where the installation sets
`host_shell_needs_approval`, another administrator approves the shell before the runner is
touched. Every session is recorded by the control plane and kept in the logs bucket under Object
Lock.

Once the shell has ended, the runner is retired: it is revoked, every disk it held the key of is
marked to be re-keyed, and its machine is replaced by its group.

## A workspace's bandwidth

An administrator
[changes a running workspace's bandwidth, and its open connections stay open](<feature:An administrator changes a running workspace's bandwidth, its connections open>).

```bash
spin workspace bandwidth <id> <mbps> # megabits a second, each way; 0 lifts the limit
```

A stopped or suspended workspace takes the value at its next start. The limit bounds what a
workspace can cost in egress, so its owner may not raise it.

## Writeback on a host

A runner's policy can carry
[a writeback bound of its own, measured on that host first](<feature:A writeback bound per host, measured on that host before it is taken>).

```bash
spin admin runner policy <runner-id>
spin admin runner policy <runner-id> --writeback-limit-bytes <bytes> --writeback-background-bytes <bytes>
```

With no flags the command shows the policy. Any flag writes the whole policy: a setting you do not
pass goes back to the runner's own default. Thresholds that no preset names are refused until
that host has been tested with them. The test is
[TestHostWriteback](/reference/api/hostservice/#testhostwriteback), and it loads the host's disk
while it runs.
12 changes: 6 additions & 6 deletions src/content/docs/admin/users.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@ reads:

## Signing in

A user signs in to the dashboard with:
[A user signs in to the dashboard with](<feature:Sign in with GitHub or an OIDC provider>):

- **GitHub**, or
- **any OIDC provider**: your company's identity provider, Google, Microsoft Entra ID, Okta and
others that speak OpenID Connect.

Providers are configured in **Admin → Security**. A provider can be the installation's, or a
team's own. Spinbox has no multi-factor authentication of its own: require it in your provider.
Providers are configured in **Admin → Security**. [A provider can be the installation's, or a
team's own](<feature:A team's own identity providers>). Spinbox has no multi-factor authentication of its own: require it in your provider.

The first administrator signs in with a password, from the one-time password the install wrote.
Once a provider works, password sign-in can be turned off.

The CLI signs in through the dashboard, with a code the user approves (see [The CLI](/use/cli/)).
The CLI signs in through the dashboard, [with a code the user approves](<feature:Device login for a terminal>) (see [The CLI](/use/cli/)).
Sessions last seven days by default.

## Who may register
Expand All @@ -46,7 +46,7 @@ adds.

| Role | Can |
|---|---|
| Owner | Everything, including deleting the team. One per team. |
| [Owner](<feature:Teams, with owner, admin and member>) | Everything, including deleting the team. One per team. |
| Admin | Manage members and the team's settings |
| Member | Have workspaces in the team |

Expand Down Expand Up @@ -74,6 +74,6 @@ the `keys:delegate` scope, each holding no more than it does. See

## The audit log

**Admin → Audit** lists who did what: sign-ins and failed sign-ins, sessions revoked, workspaces
**Admin → Audit** [lists who did what](<feature:An audit log>): sign-ins and failed sign-ins, sessions revoked, workspaces
created, started, stopped, recovered and deleted, changes to teams, to settings and to users, and
runners registered. Nothing in the API can change or delete an entry.
11 changes: 6 additions & 5 deletions src/content/docs/concepts/network.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ allows them all.

**DNS follows the policy.** A workspace's resolver is the runner's, so no policy needs to open
port 53. A DNS question leaves from the runner, where no firewall rule sees it, and reaches whoever
answers that name, so the resolver only takes up the ones a workspace's policy names:
answers that name, so [the resolver only takes up the ones a workspace's policy names](<feature:A workspace's DNS goes upstream only for what its policy names, so a policy that closes egress closes the tunnel through names>):

- A workspace with no tag, or with a rule that reaches every address (ports with no destination,
or `0.0.0.0/0`), resolves anything. DNS gives it nothing it could not already do.
Expand All @@ -89,20 +89,21 @@ spin workspace policies # the policies you can choose f
spin workspace retag api --network-tag web --network-tag agent
```

The owner can choose among the policies the installation declares. Removing a policy from a
The owner can choose among the policies the installation declares. A team declares
[policies of its own](<feature:A team's own network policies, where the installation allows them>) where the installation allows it (`team_network_policies`). Removing a policy from a
running workspace closes the connections it had open, not only new ones.

Administrators declare policies in the [installation settings](/admin/configuration/) or in the
dashboard (Admin → Network), which shows for each one whether every runner enforces the
current version.
dashboard (Admin → Network), [which shows for each one whether every runner enforces the
current version](<feature:A policy changed reaches the host that runs the workspace>).

## Seeing what happened

```bash
spin workspace egress api
```

shows what the workspace reached in the last six hours, with the most traffic first, the names
shows [what the workspace reached in the last six hours](<feature:What a workspace reached, what it looked up and what it was refused>), with the most traffic first, the names
it looked up that failed, and what was refused in the last hour, with the name it was looked up
by. The workspace's **Network** tab in the dashboard shows the same. When something does not
work, the refused list tells you which policy is too narrow.
Expand Down
4 changes: 2 additions & 2 deletions src/content/docs/concepts/ports.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ reads:
- "spin:cmd/cli/cmd/share.go@v20261108.01"
---

A service listening on a TCP port in a workspace can be reached through the installation's
proxy, at its own HTTPS address:
A service listening on a TCP port in a workspace [can be reached through the installation's
proxy, at its own HTTPS address](<feature:Published ports at https://{port}-{workspace}.{domain}: private, whitelisted or public>):

```
https://<port>-<workspace>.ws.<domain>
Expand Down
116 changes: 116 additions & 0 deletions src/content/docs/concepts/projects.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
---
title: Projects and repositories
description: How a project ties a repository to the shape of its workspace, and how you open one from a URL, prebuild its refs and connect your GitHub account.
reads:
- "spin:cmd/cli/cmd/project.go@v20261110.01"
- "spin:cmd/cli/cmd/project_prebuild.go@v20261110.01"
- "spin:cmd/cli/cmd/open.go@v20261110.01"
- "spin:cmd/cli/cmd/git.go@v20261110.01"
---

A project is [a repository and the shape of the workspace that opens it](<feature:Projects of the installation: a repository and the shape of the workspace that opens it, shared with everyone or some>).
The shape is the image, the preset and the network policies. The project also names the ref a
workspace opens at.

The guest of a workspace made from a project clones the repository into
`/workspace/<repository name>` and runs the repository's own `.spin.yaml` tasks there.

## Making and sharing a project

Projects belong to the installation. Whoever makes one is its admin. An installation can keep
making projects to its administrators, with `project_creation` in the
[configuration file](/reference/configuration/file/).

```bash
spin project create --name <name> --repository <https-url> --ref <branch> --preset <preset>
spin project list
```

Everybody signed in sees a project until its admins share it with only some people and teams.
A share is saved whole: what you do not name is no longer shared. Admins always see the project.

```bash
spin project share <slug> --team <team> --admin <user-id>
spin project share <slug> --everyone --admin <user-id>
```

Whoever sees a project opens workspaces from it, in a team of theirs. See
[spin project](/reference/cli/project/).

## Opening from a URL

You can [open a repository, a branch, a commit or a pull request from its URL](<feature:Open a repository, branch, commit or pull request from its URL, in the dashboard (/launch) and from the terminal>):
on the dashboard's `/launch` page, or from the terminal with [spin open](/reference/cli/open/).

```bash
spin open https://github.com/<owner>/<repository>
spin open https://github.com/<owner>/<repository>/tree/<branch>
spin open https://github.com/<owner>/<repository>/commit/<sha>
spin open https://github.com/<owner>/<repository>/pull/<n>
```

The project is found by its repository among the projects you see. When more than one has it,
`--project` says which. A repository no project has is one to make a project of first.

A plain repository URL opens at the project's ref. A workspace can also be
[opened at a commit or at a pull request, which is checked out as `pr-<n>`](<feature:A workspace opened at a commit or a pull request, checked out as pr-%3Cn%3E>).

The workspace is made in `--team`, or in your personal team, and sized by the project's preset
unless `--preset` names another. `spin open` ends in `spin ssh`,
unless you pass `--no-connect`.

To open a project by its slug instead of a URL:

```bash
spin workspace create --project <slug> --ref <branch-or-tag>
```

## Prebuilds

A project can name refs to prebuild. Each one is built as it moves, and the result is a
snapshot. [A workspace that opens the project at that ref is cloned from its prebuild](<feature:Prebuilds of a project's refs, as the floor of the workspaces that open them>),
so it starts from what the build already made. The builds run as the person who named the refs.

```bash
spin project create --name <name> --repository <https-url> --ref <branch> --prebuild-ref <branch>
spin project prebuilds <slug>
spin project prebuild <slug> <ref>
```

`spin project prebuilds` lists each build of a ref at a commit and what became of it.
`spin project prebuild` builds a ref now, at the commit the forge says it is at. A commit whose
build failed is built again. Only the project's admins can run it.

An installation can retire a ready prebuild that no workspace has opened for a while. The
project's next open then starts from the image. See [Snapshots](/concepts/snapshots/).

## Your GitHub account

A private repository on GitHub is cloned with the workspace owner's own account. You
[connect your GitHub account once](<feature:Your GitHub account, connected once: private repositories cloned and pushed with nothing on the disk>),
and it clones and pushes your workspaces' private repositories. The control plane keeps the
token. The host your workspace runs on sets it on the requests a network policy brokers to
GitHub, so no workspace's disk holds it.

Connect in the dashboard, under Settings → Git, or
[from the CLI, with a code you enter on GitHub's page](<feature:Your GitHub account connected from the CLI, with a code entered on GitHub's page>):

```bash
spin git connect
spin git list
```

Either way, GitHub asks you to authorize the installation's app. The token never reaches your
machine. `spin git connect` needs "Enable Device Flow" checked on the installation's GitHub App.

To choose a repository for a project,
[list the repositories your account reaches](<feature:A repository picked from the ones your account reaches>),
or only those whose name has a query in it:

```bash
spin git repos
spin git repos <query>
```

`spin git disconnect github` forgets the account and has GitHub revoke the token. See
[spin git](/reference/cli/git/).
Loading
Loading