Reference

Command-line tools

On this page

The deltaglider_proxy binary is both the server and its CLI. With no subcommand it starts the server; with a subcommand (or one of the run-and-exit flags below) it runs to completion and exits without starting the server.

Flags#

FlagEffect
-c, --config <FILE>Path to the config file (global; also honored by subcommands)
-l, --listen <ADDR>Listen address, overrides config
-v, --verboseVerbose logging (trace). RUST_LOG, DGP_LOG_LEVEL and a log_level that the config file sets win over it
--initInteractive configuration wizard, then exit
--set-bootstrap-passwordRead a password from stdin, write its bcrypt hash, then exit (alias: --set-admin-password)
--show-envPrint all DGP_* environment variables in .env format, then exit
--versionVersion plus build timestamp

Exit codes#

All subcommands share one set of exit codes: 0 OK, 2 usage, 3 I/O error, 4 parse error, 5 HTTP error, 6 rejected by validation/server, 7 authentication failure, 8 S3 not found, 9 integrity (hash mismatch), 10 partial success in a recursive operation.

config lint#

deltaglider_proxy config lint <FILE>

config lint validates a file offline. It uses the same pipeline as the admin API's /config/validate: shape classification, deny-unknown-fields, shorthand normalization, admission-block semantics, Config::check warnings (including the cross-field config advisories: shared rate-limit bucket, stale IAM template, frozen quota, redundant public prefix). The command first expands ${env:NAME} / ${env:NAME:-default} references against the environment. An unset variable without a default fails the lint. YAML is the only supported format. A .toml input fails with the TOML-removed error (TOML support was removed in v1.4.1; convert the file with config migrate on v1.4.0). Warnings go to stderr and are non-fatal. An unknown root key of a flat-shape document is an error, although the proxy loads such a file and ignores the key. Exit: 0 valid (with or without warnings), 3 unreadable, 4 parse error (also an unknown key, an unset ${env:NAME} without a default, and an empty or whitespace-only file, which an apply would refuse because it resets every field), 6 validation error (including an unparseable log_level filter, and a lifecycle or replication rule that an apply refuses, such as two replication rules with the same name).

config schema#

deltaglider_proxy config schema [--out <OUTPUT>]

Emits the JSON Schema for the canonical sectioned document, with the admission, access, storage and advanced sections at the root. This is the shape that config export and every admin save write. The schema comes from the schemars derives, so it follows the code automatically. Every field that is not text, such as a boolean, a number or a choice from a list, also accepts a whole ${env:NAME} or ${env:NAME:-default} reference, because the proxy gives the expanded value the type of the field. CI and YAML LSP autocompletion consume the schema.

config defaults#

deltaglider_proxy config defaults [--out <OUTPUT>]

Emits per-field defaults and doc-comment descriptions as JSON Schema. The output is currently identical to that of config schema. The two commands are separate entry points, and their output may diverge in future releases.

config apply#

deltaglider_proxy config apply <FILE> [--server <URL>] [--timeout <SECS>] [--confirm-key-removal <KEY_ID>]... [--confirm-encryption-downgrade <SUBJECT>]...

Sends a full YAML document to a running server with POST /_/api/admin/config/apply. The server validates the document, swaps the runtime config atomically, and persists it. Before the command sends the document, it expands ${env:NAME} references against the environment of the operator. The command refuses an empty rendered body.

The command reads the password from the DGP_BOOTSTRAP_PASSWORD environment variable. It does not take the password as a flag, because ps listings show the command line. The command logs in, holds the session cookie in memory only, and discards it on exit. Defaults: --server http://127.0.0.1:9000, --timeout 30. A cleartext http:// URL to a non-loopback host produces a warning. The command echoes the warnings of the server to stderr verbatim.

--confirm-key-removal <KEY_ID> (repeatable) confirms that the apply may remove that legacy (decrypt-only) key id from a bucket's encryption block. The server refuses such an apply without the confirmation, because objects that still carry the id would become unreadable. Run the legacy-key usage scan first (per-bucket encryption).

--confirm-encryption-downgrade <SUBJECT> (repeatable) confirms that the apply may make a bucket store new objects in plaintext where it encrypted them before. The subject is a bucket name, backend:<name> for every bucket that inherits the encryption of that backend, or route:default for the buckets that the config does not name (a new default_backend). With config_sync_bucket set, a confirmed subject is also published to the encryption witness when the config does not change, which finishes a downgrade that the instances got by restart. The server refuses such an apply without the confirmation (a downgrade needs a confirmation).

Exit: 0 applied and persisted (with a stderr note when a restart-only field changed); 5 applied in memory but not persisted (also HTTP errors and login rate-limiting); 6 server rejected the apply; 7 missing/wrong DGP_BOOTSTRAP_PASSWORD; 3 local I/O error.

witness publish#

deltaglider_proxy witness publish <SUBJECT>... [--confirm-encryption-downgrade <SUBJECT>]... [--server <URL>] [--timeout <SECS>]

With config_sync_bucket set, publishes the encryption that this instance uses for the named storages as the encryption that every instance must use. Use it after a rollout that restarted the instances with a changed config (a ConfigMap, a new environment key): a restart does not publish, so the changed buckets refuse writes until you run it. A subject is a bucket name, backend:<name> or route:default. A storage that this instance stores in plaintext needs --confirm-encryption-downgrade <SUBJECT>. The command reads the password from DGP_BOOTSTRAP_PASSWORD, like config apply, and prints the published storages as JSON. See run multiple instances.

Exit: 0 published; 6 refused (a subject that names no storage, an unconfirmed downgrade, or a single instance); 5 the sync bucket did not answer, or another HTTP error; 7 missing/wrong DGP_BOOTSTRAP_PASSWORD.

admission trace#

deltaglider_proxy admission trace --method <M> --path <P> [--authenticated] [--query <Q>] [--server <URL>] [--timeout <SECS>]

Sends a synthetic request through the admission chain of the running server as a dry run, with POST /_/api/admin/config/trace. The command prints the decision as pretty JSON on stdout, which you can pipe to jq. It uses the same DGP_BOOTSTRAP_PASSWORD authentication, --server/--timeout defaults, and exit codes as config apply.

--init#

--init starts an interactive wizard in the style of npm init. The wizard prompts for the output path (default deltaglider_proxy.yaml), listen address, log level, backend (filesystem or S3 with endpoint/region/credentials), delta settings (max_delta_ratio, max object size, cache size), optional SigV4 credentials, and optional TLS. Every file that the wizard writes starts the proxy. When you enable SigV4 authentication and leave the key prompts empty, the wizard generates the key pair and prints the secret. The proxy refuses to start without credentials unless the file sets authentication: none. For this reason, when you decline authentication, the wizard writes authentication: none. Use that file for development only. The wizard prints the generated config for confirmation before it writes the file. It asks for an explicit confirmation before it overwrites an existing file. The output is always canonical sectioned YAML (a .toml output path is refused).

--set-bootstrap-password#

Reads one line from stdin, validates password quality, and writes the bcrypt hash to .deltaglider_bootstrap_hash in the working directory. It also prints the base64-encoded hash for DGP_BOOTSTRAP_PASSWORD_HASH (avoids $ escaping in Docker/env files). The flag does not change the IAM database, because the key of the database is DGP_CONFIG_DB_KEY or the key file next to the database. If the database is still encrypted with the old hash (a database from a release before the config DB key), the flag first re-encrypts it with the config DB key. Exit: 0, or 1 on empty/weak password, or when the database opens with neither the config DB key nor the current hash (the hash is then not changed).

s3 client command family#

The s3 verbs are client commands shaped like the AWS CLI. They talk directly to an S3 endpoint (no running proxy is required), and they read and write the same delta-storage layout that the proxy uses. The metadata that these verbs write is bit-compatible with the metadata that the proxy writes.

Point these verbs at the storage backend, not at the proxy. Each verb runs its own copy of the delta engine, so it writes and reads the delta-storage layout (reference.bin baselines and .delta objects) itself. The proxy refuses requests for these internal key names from S3 clients, and it already applies delta compression to every object that it stores. For these two reasons, the s3 verbs cannot work through the proxy. Before a verb (ls, cp, rm, sync, stats, verify, migrate, purge, get-bucket-acl, put-bucket-acl) sends a request, it sends one unauthenticated GET /_/health to --endpoint-url. When the answer comes from a DeltaGlider Proxy, the verb stops with exit code 2 and a message that says so. To store objects through the proxy, use any plain S3 client, for example aws s3 --endpoint-url https://s3.acme.example.

Do not run the write and delete verbs on prefixes that a running proxy writes. The verbs cp, sync, rm and migrate change the same reference.bin baselines and .delta objects that the proxy changes. The proxy locks a prefix while it writes there, but it keeps that lock in its own memory, and a CLI process keeps its own lock in the same way. Neither process can see the lock of the other one. So when rm deletes the last object of a prefix, it also deletes the reference.bin of that prefix, and a delta that the proxy stores at the same moment can lose the baseline that it needs. The proxy can then not rebuild that object. Run these verbs on a prefix only when no proxy writes to it, for example on a backend before you put a proxy in front of it, or during a maintenance window. Before a write or delete verb sends its first request, it prints this rule once to stderr. The --quiet flag hides the note, and a --dryrun (for migrate, --dry-run) does not print it.

CommandPurpose
s3 lsList buckets or objects
s3 cpCopy between local paths and S3 with transparent delta compression
s3 rmRemove objects (single key or recursive prefix delete)
s3 syncSync a directory between local and S3, or between two S3 prefixes
s3 statsBucket statistics: original/stored bytes, savings %, deltaspace health
s3 verifySHA256 round-trip integrity check of a stored object
s3 migrateMigrate a deltaspace between buckets/accounts through the engine
s3 purgePurge expired Python-toolchain rehydration cache entries (.deltaglider/tmp/*)
s3 get-bucket-acl / s3 put-bucket-aclRead / update a bucket ACL (canned-ACL or grant flags)

Exit codes 8 (not found), 9 (integrity), and 10 (partial) are specific to this family. --help on each verb lists its flags.

Credentials#

The s3 verbs read credentials in this order: the --access-key-id and --secret-access-key flags, then the AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN environment variables, then the profile in ~/.aws/credentials (selected by --profile, then AWS_PROFILE, then default). A session token from the environment or from the profile's aws_session_token is sent with every request, so temporary (STS) credentials work. The --secret-access-key flag is deprecated, because other users on the same host can read a command line (for example with ps). When you use the flag, the verb prints a warning to stderr. The next major release removes the flag, so set AWS_SECRET_ACCESS_KEY or use a profile instead.

Recursive prefixes#

cp -r, rm -r, sync, and migrate treat a non-empty source prefix as a directory. s3://releases/v2 and s3://releases/v2/ both select only the keys under v2/. They do not select keys under a sibling such as v2-rc/, and they do not select an object whose key is exactly v2. This rule is stricter than aws s3 rm --recursive, which matches the raw prefix.

rm -r deletes each key with its own request, folder markers (keys that end with /) included. It also deletes the folder marker of the directory itself, such as the key v2/, when no --include or --exclude glob narrows the delete.

A download (cp -r or sync from S3 to a local directory) writes only below the destination directory. The CLI skips a key that contains an empty path segment (for example a leading / or //), a . or .. segment, a backslash, a drive letter such as C:, or a NUL byte. It prints a warning for each skipped key, and the command exits with 10 (partial) or 5. The CLI also skips folder markers (keys that end with /) without a warning.

Include and exclude globs#

--include and --exclude match the key relative to the source prefix, in cp -r, rm -r, sync, and migrate. A glob without a / matches the last path segment of the key (*.zip). A glob with a / matches the whole relative key: rm -r s3://releases/v2/ --exclude 'tmp/*' keeps v2/tmp/. When a key matches both an include and an exclude glob, the exclude glob wins.

S3-to-S3 copies#

cp, sync, and migrate between two S3 locations keep the source object's Content-Type and user metadata. A --metadata K=V flag on cp replaces the value of that key. Cache-Control, Content-Disposition, and Content-Encoding are not copied.

Object size and memory#

cp, sync, migrate, and verify do not hold a large object in memory. An object of 8 MiB or less is read into memory, because a spool copy costs more than it saves for a small file. A larger upload is first copied into a spool file (in DGP_SPOOL_DIR, within the DGP_SPOOL_MAX_BYTES budget) and then stored from that file. A download writes the object to a temporary file beside the destination and renames the file into place at the end, so a failed download does not leave a truncated file. An S3-to-S3 copy writes the source into a spool file first. verify hashes the object while it reads it. The engine itself reconstructs a delta object in memory when the object is 16 MiB or smaller, and in a spool file when it is larger. The verbs do not read DGP_SPOOL_THRESHOLD_BYTES or the proxy config file, so this threshold is fixed; it is lower only when --max-object-size-mb is lower. The verbs do read DGP_SPOOL_DIR and DGP_SPOOL_MAX_BYTES.

--no-delta on cp, sync, and migrate stores each object as a plain object, without a delta against the reference.bin baseline. The verb sends the user metadata dg-no-delta: true, and the engine does not store this hint with the object. An S3 client that stores through the proxy can send the same hint as the header x-amz-meta-dg-no-delta: true.

--max-object-size-mb sets the size limit of a delta (default 100 MiB), because the xdelta3 work grows with the object size. A delta-eligible file that is larger is stored whole, like any other file, up to 64 GiB, the default of max_passthrough_object_size. The verbs do not read the proxy config file, so no setting changes this limit.

s3 verify results#

OutputExit codeMeaning
OK0The SHA-256 of the downloaded bytes matches the checksum that DeltaGlider stored with the object.
UNVERIFIABLE0The object has no DeltaGlider checksum, because another tool wrote it. The download succeeded, and the line shows the SHA-256 of the bytes.
MISMATCH9The SHA-256 of the downloaded bytes differs from the stored checksum, or the engine found a checksum error while it reconstructed a delta.
error: object not found or error: bucket not found8The key or the bucket does not exist.