mirror of
https://github.com/neondatabase/neon.git
synced 2026-01-15 09:22:55 +00:00
This PR adds support for supplying the tenant config upon /attach. Before this change, when relocating a tenant using `/detach` and `/attach`, the tenant config after `/attach` would be the default config from `pageserver.toml`. That is undesirable for settings such as the PITR-interval: if the tenant's config on the source was `30 days` and the default config on the attach-side is `7 days`, then the first GC run would eradicate 23 days worth of PITR capability. The API change is backwards-compatible: if the body is empty, we continue to use the default config. We'll remove that capability as soon as the cloud.git code is updated to use attach-time tenant config (https://github.com/neondatabase/neon/issues/4282 keeps track of this). unblocks https://github.com/neondatabase/cloud/issues/5092 fixes https://github.com/neondatabase/neon/issues/1555 part of https://github.com/neondatabase/neon/issues/886 (Tenant Relocation) Implementation ============== The preliminary PRs for this work were (most-recent to least-recent) * https://github.com/neondatabase/neon/pull/4279 * https://github.com/neondatabase/neon/pull/4267 * https://github.com/neondatabase/neon/pull/4252 * https://github.com/neondatabase/neon/pull/4235
48 lines
1.5 KiB
Rust
48 lines
1.5 KiB
Rust
use anyhow::Context;
|
|
use bytes::Buf;
|
|
use hyper::{header, Body, Request, Response, StatusCode};
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use super::error::ApiError;
|
|
|
|
pub async fn json_request<T: for<'de> Deserialize<'de>>(
|
|
request: &mut Request<Body>,
|
|
) -> Result<T, ApiError> {
|
|
json_request_or_empty_body(request)
|
|
.await?
|
|
.context("missing request body")
|
|
.map_err(ApiError::BadRequest)
|
|
}
|
|
|
|
/// Will be removed as part of https://github.com/neondatabase/neon/issues/4282
|
|
pub async fn json_request_or_empty_body<T: for<'de> Deserialize<'de>>(
|
|
request: &mut Request<Body>,
|
|
) -> Result<Option<T>, ApiError> {
|
|
let body = hyper::body::aggregate(request.body_mut())
|
|
.await
|
|
.context("Failed to read request body")
|
|
.map_err(ApiError::BadRequest)?;
|
|
if body.remaining() == 0 {
|
|
return Ok(None);
|
|
}
|
|
serde_json::from_reader(body.reader())
|
|
.context("Failed to parse json request")
|
|
.map(Some)
|
|
.map_err(ApiError::BadRequest)
|
|
}
|
|
|
|
pub fn json_response<T: Serialize>(
|
|
status: StatusCode,
|
|
data: T,
|
|
) -> Result<Response<Body>, ApiError> {
|
|
let json = serde_json::to_string(&data)
|
|
.context("Failed to serialize JSON response")
|
|
.map_err(ApiError::InternalServerError)?;
|
|
let response = Response::builder()
|
|
.status(status)
|
|
.header(header::CONTENT_TYPE, "application/json")
|
|
.body(Body::from(json))
|
|
.map_err(|e| ApiError::InternalServerError(e.into()))?;
|
|
Ok(response)
|
|
}
|