Skip to content
Draft
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
69 changes: 69 additions & 0 deletions open-api/rest-catalog-open-api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1175,6 +1175,53 @@ class RemoteSignResult(BaseModel):
headers: MultiValuedMap


class RemoteSignBatchElement(BaseModel):
"""
The fields of one request in a batch that are not repeated with the other requests.
"""

uri: str
headers: MultiValuedMap
body: str | None = Field(
None,
description='Optional body of the request to send to the signing API, as in `RemoteSignRequest`.',
)


class CompletedSignResult(RemoteSignResult):
"""
A successfully signed batch element
"""

index: int = Field(
..., description='The 0-based position of the element in `requests`', ge=0
)


class FailedSignResult(BaseModel):
"""
A batch element that could not be signed
"""

index: int = Field(
..., description='The 0-based position of the element in `requests`', ge=0
)
error: ErrorModel


class RemoteSignBatchResponse(BaseModel):
"""
The result of a batch remote request signing operation.
"""

completed: list[CompletedSignResult] = Field(
..., description='Elements that were signed'
)
failed: list[FailedSignResult] = Field(
..., description='Elements that could not be signed'
)


class RemoteSigningConfig(BaseModel):
"""
Configuration for the remote signer client.
Expand All @@ -1188,6 +1235,12 @@ class RemoteSigningConfig(BaseModel):
None,
description='Static headers the signer client MUST include unchanged in every request to the signing endpoint.\n',
)
sign_batch_max_size: int | None = Field(
None,
alias='sign-batch-max-size',
description='The maximum number of elements in one `batchSignRequests` request for this table.',
ge=1,
)


class CreateNamespaceRequest(BaseModel):
Expand Down Expand Up @@ -1370,6 +1423,22 @@ class FetchScanTasksRequest(BaseModel):
plan_task: PlanTask = Field(..., alias='plan-task')


class RemoteSignBatchRequest(BaseModel):
"""
A batch of requests to be signed remotely. `region`, `method`, `provider` and `properties` apply to every element of `requests`.

"""

region: str
method: Literal['PUT', 'GET', 'HEAD', 'POST', 'DELETE', 'PATCH', 'OPTIONS']
provider: str = Field(
...,
description='The storage provider for every element of the batch. The provider should correspond to the scheme used for a storage native URI. For example `s3` for AWS S3 paths.',
)
properties: dict[str, str] | None = None
requests: list[RemoteSignBatchElement] = Field(..., min_length=1)


class Term(RootModel[TermReference | TransformTerm]):
root: TermReference | TransformTerm = Field(
...,
Expand Down
169 changes: 169 additions & 0 deletions open-api/rest-catalog-open-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1429,6 +1429,59 @@ paths:
5XX:
$ref: '#/components/responses/ServerErrorResponse'

/v1/{prefix}/namespaces/{namespace}/tables/{table}/sign/batch:
parameters:
- $ref: '#/components/parameters/prefix'
- $ref: '#/components/parameters/namespace'
- $ref: '#/components/parameters/table'
- $ref: '#/components/parameters/data-access'

post:
tags:
- Catalog API
summary: Remotely signs a batch of requests to object storage
operationId: batchSignRequests
description:
Signs a batch of requests to object storage on the client's behalf.


A server that supports this operation for a table MUST set `sign-batch-max-size` in the
table's `RemoteSigningConfig`. A client MUST NOT send more elements than that value. A
batch above the server's limit is rejected with 413.


A 200 response means the batch was processed. Each element of `requests` is reported once,
by its 0-based index, in either `completed` or `failed`.


`X-Iceberg-Access-Delegation` applies to the batch as a whole.
requestBody:
description: The batch of requests to be signed
content:
application/json:
schema:
$ref: '#/components/schemas/RemoteSignBatchRequest'
required: true
responses:
200:
$ref: '#/components/responses/RemoteSignBatchResponse'
400:
$ref: '#/components/responses/BadRequestErrorResponse'
401:
$ref: '#/components/responses/UnauthorizedResponse'
403:
$ref: '#/components/responses/ForbiddenResponse'
406:
$ref: '#/components/responses/UnsupportedOperationResponse'
413:
$ref: '#/components/responses/BatchContentTooLargeResponse'
419:
$ref: '#/components/responses/AuthenticationTimeoutResponse'
503:
$ref: '#/components/responses/ServiceUnavailableResponse'
5XX:
$ref: '#/components/responses/ServerErrorResponse'

/v1/{prefix}/tables/rename:
parameters:
- $ref: '#/components/parameters/prefix'
Expand Down Expand Up @@ -5466,6 +5519,96 @@ components:
headers:
$ref: '#/components/schemas/MultiValuedMap'

RemoteSignBatchRequest:
description: >
A batch of requests to be signed remotely. `region`, `method`, `provider` and
`properties` apply to every element of `requests`.
type: object
required:
- region
- method
- provider
- requests
properties:
region:
type: string
method:
type: string
enum: ["PUT", "GET", "HEAD", "POST", "DELETE", "PATCH", "OPTIONS"]
provider:
type: string
description: The storage provider for every element of the batch. The provider should correspond
to the scheme used for a storage native URI. For example `s3` for AWS S3 paths.
properties:
type: object
additionalProperties:
type: string
requests:
type: array
minItems: 1
items:
$ref: '#/components/schemas/RemoteSignBatchElement'

RemoteSignBatchElement:
description: The fields of one request in a batch that are not repeated with the other requests.
type: object
required:
- uri
- headers

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think headers need to be required.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, but I grandfathered this one in from the singular RemoteSignRequest

I know it is required in RemoteSignRequest for backward compatibility even after introducing remote-presigning (#18080) - do we want to divert away from that here? I was worried that it would be confusing to have different nullability semantic for the two

properties:
uri:
type: string
headers:
$ref: '#/components/schemas/MultiValuedMap'
body:
type: string
description: Optional body of the request to send to the signing API, as in `RemoteSignRequest`.

CompletedSignResult:
description: A successfully signed batch element
allOf:
- $ref: '#/components/schemas/RemoteSignResult'
- type: object
required:
- index
properties:
index:
type: integer
minimum: 0
description: The 0-based position of the element in `requests`

FailedSignResult:
description: A batch element that could not be signed
type: object
required:
- index
- error
properties:
index:
type: integer
minimum: 0
description: The 0-based position of the element in `requests`
error:
$ref: '#/components/schemas/ErrorModel'

RemoteSignBatchResponse:
description: The result of a batch remote request signing operation.
type: object
required:
- completed
- failed
properties:
completed:
description: Elements that were signed
type: array
items:
$ref: '#/components/schemas/CompletedSignResult'
failed:
description: Elements that could not be signed
type: array
items:
$ref: '#/components/schemas/FailedSignResult'

RemoteSigningConfig:
description: Configuration for the remote signer client.
type: object
Expand All @@ -5483,6 +5626,10 @@ components:
description: >
Static headers the signer client MUST include unchanged in every request to the signing
endpoint.
sign-batch-max-size:
type: integer
minimum: 1
description: The maximum number of elements in one `batchSignRequests` request for this table.

#############################
# Reusable Response Objects #
Expand Down Expand Up @@ -5662,6 +5809,21 @@ components:
}
}

BatchContentTooLargeResponse:
description:
The batch has more elements than the server accepts, as set in `sign-batch-max-size`.
content:
application/json:
schema:
$ref: '#/components/schemas/IcebergErrorResponse'
example: {
"error": {
"message": "Batch exceeds the maximum of 100 elements",
"type": "ContentTooLargeException",
"code": 413
}
}

ServiceUnavailableResponse:
description:
The service is not ready to handle the request, request could have been partially processed.
Expand Down Expand Up @@ -5800,6 +5962,13 @@ components:
schema:
$ref: '#/components/schemas/RemoteSignResult'

RemoteSignBatchResponse:
description: The outcome of signing each element of a batch.
content:
application/json:
schema:
$ref: '#/components/schemas/RemoteSignBatchResponse'

#######################################
# Common examples of different values #
#######################################
Expand Down
Loading