refactor: align storage:set with dokku conventions

`storage:set` now takes `<name> <property> [<value>]` like every other `:set` command, where omitting the value unsets the property. Previously it took flags and could not distinguish an empty value from an omitted one, so nothing it set could ever be cleared. The flag form keeps working and emits a deprecation warning.

Annotations and labels move to `storage:annotations:set`, `storage:annotations:report`, `storage:labels:set`, and `storage:labels:report`, matching the `scheduler-k3s` equivalents. These operate on a single key, so clearing one leaves the rest in place rather than replacing the whole map as the `--annotation` and `--label` flags do.
This commit is contained in:
Jose Diaz-Gonzalez
2026-08-10 15:00:45 -04:00
parent 87b240054f
commit 74f9acf7ba
12 changed files with 1624 additions and 500 deletions

View File

@@ -6,18 +6,22 @@
The preferred method to attach persistent storage to a Dokku-managed container is the Dokku storage plugin.
```
storage:annotations:report [<name>] [<flag>] # Display annotations for one or more storage entries
storage:annotations:set <name> <key> [<value>] # Set or clear a single annotation on a storage entry
storage:create <name> [<path>] [flags] # Register a named storage entry
storage:destroy <name> [--force] [--destroy-host-dir] # Remove a named storage entry (must be unmounted from every app first)
storage:ensure-directory [--chown option] <directory> # [DEPRECATED] use storage:create instead
storage:exec <name> [-- <cmd>...] # Run a command (or shell) in a temporary container that mounts the entry
storage:info <name> [--format text|json] # Show details for one storage entry
storage:labels:report [<name>] [<flag>] # Display labels for one or more storage entries
storage:labels:set <name> <key> [<value>] # Set or clear a single label on a storage entry
storage:list <app> [--format text|json] # List bind mounts for an app's container(s) (legacy host:container view)
storage:list-entries [--scheduler s] [--format text|json] # List registered storage entries
storage:mount <app> <name> --container-dir <path> [flags] # Mount a named entry into an app
storage:mount <app> <host-dir:container-dir> # [LEGACY] colon-form mount, docker-local only
storage:report [<app>] [<flag>] # Display a storage report for one or more apps
storage:report --global # Display a cluster-wide entry inventory
storage:set <name> [flags] # Update a storage entry in place
storage:set <name> <property> [<value>] # Update a storage entry in place
storage:unmount <app> <name> [--container-dir <path>] # Remove an attachment
storage:wait <name> # Block until a k3s entry's PVC is bound
```
@@ -121,17 +125,23 @@ The `--chown` flag - whether on `storage:create` or `storage:ensure-directory` -
> [!IMPORTANT]
> New as of 0.38.27
Where `--chown` states who owns the host directory, `--mode` states its permission bits. It takes a 3 or 4 digit octal mode and is available on both `storage:create` and `storage:set`:
Where `--chown` states who owns the host directory, `--mode` states its permission bits. It takes a 3 or 4 digit octal mode, and is a `--mode` flag on `storage:create` and a `mode` property on `storage:set`:
```shell
dokku storage:create node-js-data --mode 0777
```
```shell
dokku storage:set node-js-data --mode 0770
dokku storage:set node-js-data mode 0770
```
Without `--mode`, a newly created directory keeps the `0755` default and a pre-existing directory keeps whatever permissions it already had. The value is stored on the entry and re-applied every time `storage:create` or `storage:set` runs against it, so a declarative caller converges the directory by re-running the same command rather than reaching for `chmod` over SSH. The mode is shown by `storage:info`:
Omitting the value clears the mode, leaving the directory's permissions alone on subsequent runs:
```shell
dokku storage:set node-js-data mode
```
Without a mode, a newly created directory keeps the `0755` default and a pre-existing directory keeps whatever permissions it already had. The value is stored on the entry and re-applied every time `storage:create` or `storage:set` runs against it, so a declarative caller converges the directory by re-running the same command rather than reaching for `chmod` over SSH. The mode is shown by `storage:info`:
```shell
dokku storage:info node-js-data
@@ -144,7 +154,85 @@ dokku storage:info node-js-data
Mode: 0777
```
`--mode` is applied to the directory itself and does not recurse into its contents. Like `--chown`, it is docker-local only and only manages the default `/var/lib/dokku/data/storage/<name>` location - it is refused for k3s entries and for entries created with a custom `<path>`.
The mode is applied to the directory itself and does not recurse into its contents. Like `--chown`, it is docker-local only and only manages the default `/var/lib/dokku/data/storage/<name>` location - it is refused for k3s entries and for entries created with a custom `<path>`. That refusal also covers migrated `legacy-*` entries, whose host paths come from the original colon-form mount rather than the default location.
### Updating a storage entry
> [!IMPORTANT]
> The property form is new as of 0.38.27. Prior versions used flags, which still work but emit a deprecation warning.
An existing entry is edited with `storage:set`, which takes a property and a value. Omitting the value unsets the property, restoring whatever the entry defaults to:
```shell
dokku storage:set node-js-data chown herokuish
dokku storage:set node-js-data chown
```
The following properties can be set:
| Property | Description | Unsetting it means |
|---|---|---|
| `chown` | Ownership preset or numeric uid for the host directory | no chown is performed |
| `mode` | Octal permissions for the host directory | permissions are left alone |
| `namespace` | Namespace holding the PVC (k3s) | the `default` namespace |
| `reclaim-policy` | Whether the underlying volume survives `storage:destroy` | `Retain` |
| `size` | PVC size (k3s) | rejected, since k3s entries require a size |
| `access-mode` | PVC access mode (k3s) | rejected, see below |
| `storage-class-name` | PVC storage class (k3s) | rejected, see below |
`access-mode` and `storage-class-name` cannot be changed on an entry that already exists, because Kubernetes cannot apply either to a bound PVC. Both a different value and an empty one are refused, since clearing is equally a change:
```shell
dokku storage:set node-js-data access-mode ReadWriteMany
```
```
! storage:set cannot change access-mode in place; recreate the entry
```
Setting `chown` or `mode` on a docker-local entry applies the change to the host directory immediately. Every other property is a metadata write, and k3s entries re-apply their helm release so the cluster picks the change up.
The older flag form - `dokku storage:set node-js-data --mode 0770` - continues to work and warns. It gained unset semantics too, so `--mode ""` clears the mode the same way omitting the positional value does.
### Annotations and labels
> [!IMPORTANT]
> New as of 0.38.27
Annotations and labels are attached to a storage entry one key at a time, matching the [scheduler-k3s equivalents](/docs/deployment/schedulers/k3s.md#setting-annotations). On k3s they propagate to both the PersistentVolumeClaim and the PersistentVolume, so backup tools like Velero and Longhorn can find the volume.
```shell
dokku storage:annotations:set node-js-data backup.velero.io/backup-volumes node-js-data
dokku storage:labels:set node-js-data app.kubernetes.io/part-of billing
```
Keys may contain `/`, as the Kubernetes-style keys above do, and are stored verbatim. To clear a single key, omit the value. Other keys are left untouched, so a declarative caller does not need to re-send the whole set on every call:
```shell
dokku storage:annotations:set node-js-data backup.velero.io/backup-volumes
```
Configured annotations and labels can be inspected with the matching report commands. Without an entry name they cover every registered entry:
```shell
dokku storage:annotations:report
dokku storage:annotations:report node-js-data
dokku storage:labels:report node-js-data
```
```
=====> node-js-data annotations information
Annotation backup.velero.io/backup-volumes: node-js-data
```
JSON output emits the keys flat, and a single value can be read directly with a flag of the form `--storage-annotations.<key>` (or `--storage-labels.<key>`), which requires an entry name:
```shell
dokku storage:annotations:report node-js-data --format json
dokku storage:annotations:report node-js-data --storage-annotations.backup.velero.io/backup-volumes
```
`storage:create` still accepts repeatable `--annotation key=value` and `--label key=value` flags for setting the initial set at creation time. The same flags on `storage:set` are deprecated in favor of these commands, because they replace the entire map rather than a single key.
### Mounting storage into apps