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
14 changes: 5 additions & 9 deletions api/common.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,10 @@ parameters:
name: cursor
in: query
description: |
Opaque cursor from the previous page's next_cursor, bound to the running
instance, the endpoint and resource it pages, the retained snapshot or
record, the filters and limit. A cursor the server no longer recognises
(snapshot expired or evicted, record left the ring, process restarted,
never issued, or issued for another endpoint or resource) returns
410 snapshot_expired; discard it and restart the walk without a cursor. A recognised cursor sent
with different filters or a different limit returns 400 invalid_request.
The server never continues a walk against a different snapshot.
Opaque cursor from the previous page's next_cursor, bound to the walk that
issued it (its snapshot or retained records, filters and limit). An unrecognised
cursor returns 410 snapshot_expired; see
[Page cursors](/v0.1.0/en/docs/errors.html#Page-cursors).
schema:
type: string
minLength: 1
Expand Down Expand Up @@ -113,7 +109,7 @@ parameters:
IfMatchOptional:
name: If-Match
in: header
description: Evaluated as RFC 9110 §13.1.1 defines; see Conditional requests in the error contract. A new group-configuration PATCH without If-Match returns 428 precondition_required; a retained idempotent replay may omit it.
description: Evaluated as RFC 9110 §13.1.1 defines; see Conditional requests in the error contract. For when a retained idempotent replay may omit it, see [Choosing the status](/v0.1.0/en/docs/errors.html#Choosing-the-status).
schema:
$ref: ./openapi.yaml#/components/schemas/EntityTagList
example: '"17"'
Expand Down
6 changes: 2 additions & 4 deletions api/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -522,9 +522,7 @@ paths:
The source's content_sha256, from GET /config or the ETag of
GET /config/sources/{source_id}, enclosed in double quotes. The server
compares it with the source's current bytes in the configuration store,
not the snapshot revision, as RFC 9110 §13.1.1 defines: `*` matches the
existing source, a list matches when any strong tag in it matches, and a
weak tag never matches.
not the snapshot revision, as [Conditional requests](/v0.1.0/en/docs/errors.html#Conditional-requests) defines.
- $ref: ./openapi.yaml#/components/parameters/IdempotencyKey
requestBody:
required: true
Expand Down Expand Up @@ -622,7 +620,7 @@ paths:
"409":
$ref: ./openapi.yaml#/components/responses/Conflict
"412":
description: If-Match does not match the stored content hash; nothing is stored
description: If-Match does not match the stored content hash, on arrival or at commit; the replacement is not stored
headers:
Cache-Control:
$ref: ./openapi.yaml#/components/headers/NoStore
Expand Down
6 changes: 2 additions & 4 deletions api/events.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@ paths:
tags: [ Events ]
summary: Follow bounded resumable invalidation events
description: |
Send stream.ready first on every connection, including a valid resume.
Its cursor must not skip pending replay; retain the supplied Last-Event-ID
until replay advances it. Filtered-out IDs may leave gaps, so clients must
not infer loss by subtracting IDs.
Every connection begins with stream.ready; a resumed connection then replays
retained events after Last-Event-ID; see [Replay and recovery](/v0.1.0/en/docs/events.html#Replay-and-recovery).
x-permission: observe
security:
- bearerAuth: []
Expand Down
6 changes: 3 additions & 3 deletions api/nodes-groups.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -642,8 +642,8 @@ paths:
A change to a field absent from mutable_config, such as
interrupt_connections on an engine without that option, returns 422
unsupported_value. Requires resources.groups.config_patch. If-Match carries the
configuration-wide revision from the ETag of GET, so an accepted change
anywhere in the configuration makes an older revision fail with 412.
configuration-wide revision from the ETag of GET; see
[Groups](/v0.1.0/en/docs/groups.html) for 412 and 409.
x-permission: control
security:
- bearerAuth: []
Expand Down Expand Up @@ -731,7 +731,7 @@ paths:
"409":
$ref: ./openapi.yaml#/components/responses/Conflict
"412":
description: If-Match does not equal the current configuration revision
description: If-Match does not match the current configuration revision, on arrival or at commit
headers:
Cache-Control:
$ref: ./openapi.yaml#/components/headers/NoStore
Expand Down
32 changes: 12 additions & 20 deletions source/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1407,9 +1407,7 @@ paths:
The source's content_sha256, from GET /config or the ETag of
GET /config/sources/{source_id}, enclosed in double quotes. The server
compares it with the source's current bytes in the configuration store,
not the snapshot revision, as RFC 9110 §13.1.1 defines: `*` matches the
existing source, a list matches when any strong tag in it matches, and a
weak tag never matches.
not the snapshot revision, as [Conditional requests](/v0.1.0/en/docs/errors.html#Conditional-requests) defines.
- $ref: '#/components/parameters/IdempotencyKey'
requestBody:
required: true
Expand Down Expand Up @@ -1514,7 +1512,7 @@ paths:
'409':
$ref: '#/components/responses/Conflict'
'412':
description: If-Match does not match the stored content hash; nothing is stored
description: If-Match does not match the stored content hash, on arrival or at commit; the replacement is not stored
headers:
Cache-Control:
$ref: '#/components/headers/NoStore'
Expand Down Expand Up @@ -3596,8 +3594,8 @@ paths:
A change to a field absent from mutable_config, such as
interrupt_connections on an engine without that option, returns 422
unsupported_value. Requires resources.groups.config_patch. If-Match carries the
configuration-wide revision from the ETag of GET, so an accepted change
anywhere in the configuration makes an older revision fail with 412.
configuration-wide revision from the ETag of GET; see
[Groups](/v0.1.0/en/docs/groups.html) for 412 and 409.
x-permission: control
security:
- bearerAuth: []
Expand Down Expand Up @@ -3685,7 +3683,7 @@ paths:
'409':
$ref: '#/components/responses/Conflict'
'412':
description: If-Match does not equal the current configuration revision
description: If-Match does not match the current configuration revision, on arrival or at commit
headers:
Cache-Control:
$ref: '#/components/headers/NoStore'
Expand Down Expand Up @@ -5169,10 +5167,8 @@ paths:
- Events
summary: Follow bounded resumable invalidation events
description: |
Send stream.ready first on every connection, including a valid resume.
Its cursor must not skip pending replay; retain the supplied Last-Event-ID
until replay advances it. Filtered-out IDs may leave gaps, so clients must
not infer loss by subtracting IDs.
Every connection begins with stream.ready; a resumed connection then replays
retained events after Last-Event-ID; see [Replay and recovery](/v0.1.0/en/docs/events.html#Replay-and-recovery).
x-permission: observe
security:
- bearerAuth: []
Expand Down Expand Up @@ -6730,14 +6726,10 @@ components:
name: cursor
in: query
description: |
Opaque cursor from the previous page's next_cursor, bound to the running
instance, the endpoint and resource it pages, the retained snapshot or
record, the filters and limit. A cursor the server no longer recognises
(snapshot expired or evicted, record left the ring, process restarted,
never issued, or issued for another endpoint or resource) returns
410 snapshot_expired; discard it and restart the walk without a cursor. A recognised cursor sent
with different filters or a different limit returns 400 invalid_request.
The server never continues a walk against a different snapshot.
Opaque cursor from the previous page's next_cursor, bound to the walk that
issued it (its snapshot or retained records, filters and limit). An unrecognised
cursor returns 410 snapshot_expired; see
[Page cursors](/v0.1.0/en/docs/errors.html#Page-cursors).
schema:
type: string
minLength: 1
Expand Down Expand Up @@ -6792,7 +6784,7 @@ components:
IfMatchOptional:
name: If-Match
in: header
description: Evaluated as RFC 9110 §13.1.1 defines; see Conditional requests in the error contract. A new group-configuration PATCH without If-Match returns 428 precondition_required; a retained idempotent replay may omit it.
description: Evaluated as RFC 9110 §13.1.1 defines; see Conditional requests in the error contract. For when a retained idempotent replay may omit it, see [Choosing the status](/v0.1.0/en/docs/errors.html#Choosing-the-status).
schema:
$ref: '#/components/schemas/EntityTagList'
example: '"17"'
Expand Down
20 changes: 13 additions & 7 deletions source/v0.1.0/en/docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,7 @@ The server refuses the following changes before storing anything:
After validation, the server commits the replacement atomically, either before
activation or after the new generation becomes active: store readers see the
old bytes or the new bytes, never a mix. Concurrent API writes serialize the
hash check, validation, and commit. At commit, a changed stored hash causes
`412`. The server starts a reload operation with `kind: reload`; on failure,
hash check, validation, and commit. The server then starts a reload operation with `kind: reload`; on failure,
`written` reports whether the store holds the replacement. The operation
succeeds only after both the commit and the activation finish; a `202` means
the server accepted the replacement, not that it is stored.
Expand All @@ -158,9 +157,16 @@ renaming it over the source, preserving the file mode.

Each write activates the candidate it validated. The next configuration write
waits until the previous activation finishes; a server that does not queue
writes returns `409 state_conflict` instead. An edit made to the store outside
the API before the commit makes the commit fail with `412`. An edit made after
the commit is not part of this activation; it takes effect at a later reload.
writes returns `409 state_conflict` instead. An edit made after the commit is
not part of this activation; it takes effect at a later reload.

The stored source can change before the commit if it is edited outside the
API. At commit the server evaluates the request's `If-Match` again against the
stored hash. If the condition no longer matches, the commit fails
with `412 stale_revision`. If the stored hash changed but the condition still
matches, as `*` or a list containing the new hash does, the commit fails with
`409 state_conflict`, because the validated candidate is stale. Either way the
replacement is not stored.

{% api_example replaceConfigSource 202 queued http %}

Expand All @@ -175,8 +181,8 @@ replacement before retrying.
|-----------------|--------------------|
| `403 permission_denied` | Missing `control`, disabled server-wide editing, a read-only source, a replacement that sets or changes API listener settings or secrets, or, in a file store, a source path that is no longer a regular file. Do not offer writes for that source. |
| `404 resource_not_found` | Unknown source ID. Refetch the accepted source set. |
| `409 state_conflict` | Another configuration write is still activating and this server does not queue writes; nothing is stored. Retry after it finishes. |
| `412 stale_revision` | The stored content hash differs from `If-Match`; the server stores nothing. Reconcile the changed source before retrying. Refetching the accepted snapshot alone may still return the old hash. |
| `409 state_conflict` | Another configuration write is still activating and this server does not queue writes, or the stored source changed before the commit while `If-Match` still matched it; nothing is stored. Retry after the write finishes, or reconcile the changed source. |
| `412 stale_revision` | `If-Match` does not match the stored content hash, on arrival or [at commit](#Validation-and-commit); the server stores nothing. Reconcile the changed source before retrying. Refetching the accepted snapshot alone may still return the old hash. |
| `422 unsupported_value` | Full validation found error diagnostics, including `restart-required`; the server stores nothing and starts no reload. Display diagnostics and correct the candidate. |
| `428 precondition_required` | `If-Match` is missing; the server writes nothing. Supply the retained source hash. |

Expand Down
7 changes: 5 additions & 2 deletions source/v0.1.0/en/docs/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ for a failed configuration change listed under
| 404 | `resource_not_found` | The requested resource does not exist. |
| 404 | `capability_not_supported` | The running engine does not expose the resource or action. |
| 405 | `method_not_allowed` | The path exists, but not with this method ([RFC 9110 §15.5.6](https://www.rfc-editor.org/rfc/rfc9110#section-15.5.6)); the response lists the supported methods in `Allow`. An unknown path is `404`. |
| 409 | `state_conflict` | The request is supported, but the current state prevents it: a name already in use, a referenced object that is not current, a transition the current state does not allow, or a configuration change while a write without `If-Match` was being admitted. The same request can succeed after the state changes. |
| 409 | `state_conflict` | The request is supported, but the current state prevents it: a name already in use, a referenced object that is not current, a transition the current state does not allow, a configuration change while a write without `If-Match` was being admitted, or a change between validation and a conditional write's commit that its `If-Match` still matches. The same request can succeed after the state changes. |
| 409 | `idempotency_conflict` | An idempotency key was reused with a different request body. |
| 409 | `event_cursor_expired` | Event or log SSE cursor cannot be replayed; open a fresh stream and establish a new baseline. |
| 409 | `setup_required` | Password login was requested before an administrator was created. |
Expand Down Expand Up @@ -108,7 +108,10 @@ The server evaluates `If-Match` as
defines. `*` matches when the resource exists. A comma-separated list matches
when any strong tag in it equals the current one. A weak tag (`W/"…"`) never
matches. A header that does not match returns `412 stale_revision`; a header
that is not `*` or a list of entity tags returns `400 invalid_request`.
that is not `*` or a list of entity tags returns `400 invalid_request`. The
server evaluates the condition again when it commits the write; a change that
the condition still matches then returns `409`, as
[validation and commit](configuration.html#Validation-and-commit) defines.

The server checks the request in the order under
[choosing the status](#Choosing-the-status): body parsing and schema checks come
Expand Down
17 changes: 10 additions & 7 deletions source/v0.1.0/en/docs/groups.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,17 @@ Updates group configuration only. It does not change runtime selection.

Use RFC 6902 JSON Patch and send the `ETag` of `GET /groups/{group_id}/config`
in `If-Match`, evaluated as [conditional requests](errors.html#Conditional-requests)
defines. A new group-configuration PATCH without `If-Match` returns `428`; a
retained idempotent replay may omit it.
defines; a retained idempotent replay may omit it, as
[choosing the status](errors.html#Choosing-the-status) describes.
Requires `resources.groups.config_patch`; without it the request
returns `404 capability_not_supported`. A group patch is a configuration
write, so `config_patch` is true only when `resources.config.writable` is.
Because `config_revision` is configuration-wide, a patch sent after an
unrelated accepted change returns `412`. Read `GET /groups/{group_id}/config`
again and retry with its current `ETag`.
Because `config_revision` is configuration-wide, an unrelated accepted change
makes an older `If-Match` fail with `412`; read `GET /groups/{group_id}/config`
again and retry with its current `ETag`. At commit the server evaluates
`If-Match` again: a mismatch returns `412`, and an intervening change that
`If-Match` still matches returns `409`, as for a
[source replacement](configuration.html#Validation-and-commit).

{% api_example patchGroupConfig request tolerance http %}

Expand Down Expand Up @@ -177,9 +180,9 @@ as a `comment`, are ignored ([RFC 6902 §4](https://www.rfc-editor.org/rfc/rfc69
|--------|---------|
| 200 | Configuration was applied; the body is the updated configuration document and `ETag` its new revision. |
| 202 | The update was accepted and returns the shared `group_update` operation summary. |
| 412 | `If-Match` does not match the current configuration-wide `config_revision`. |
| 412 | `If-Match` does not match the current configuration-wide `config_revision`, on arrival or at commit. |
| 404 | The group does not exist, or `resources.groups.config_patch` is false. |
| 409 | A `test` operation failed, or current runtime state prevents the requested transition. |
| 409 | A `test` operation failed, current runtime state prevents the requested transition, or the configuration changed before the commit while `If-Match` still matched. |
| 422 | The patch is syntactically valid but the field or value is unsupported. |
| 428 | A new patch has no `If-Match`. |

Expand Down
Loading