diff --git a/pageserver/src/http/routes.rs b/pageserver/src/http/routes.rs
index ecaeb3466f..1a5eeaea72 100644
--- a/pageserver/src/http/routes.rs
+++ b/pageserver/src/http/routes.rs
@@ -1,6 +1,6 @@
use std::sync::Arc;
-use anyhow::{bail, Context, Result};
+use anyhow::{Context, Result};
use hyper::header;
use hyper::StatusCode;
use hyper::{Body, Request, Response, Uri};
@@ -190,18 +190,27 @@ async fn timeline_list_handler(request: Request
) -> Result,
}
#[derive(Debug, Serialize)]
-struct TimelineInfo {
- #[serde(with = "hex")]
- timeline_id: ZTimelineId,
- #[serde(with = "hex")]
- tenant_id: ZTenantId,
- #[serde(with = "opt_display_serde")]
- ancestor_timeline_id: Option,
- last_record_lsn: Lsn,
- prev_record_lsn: Lsn,
- start_lsn: Lsn,
- disk_consistent_lsn: Lsn,
- timeline_state: Option,
+#[serde(tag = "type")]
+enum TimelineInfo {
+ Local {
+ #[serde(with = "hex")]
+ timeline_id: ZTimelineId,
+ #[serde(with = "hex")]
+ tenant_id: ZTenantId,
+ #[serde(with = "opt_display_serde")]
+ ancestor_timeline_id: Option,
+ last_record_lsn: Lsn,
+ prev_record_lsn: Lsn,
+ start_lsn: Lsn,
+ disk_consistent_lsn: Lsn,
+ timeline_state: Option,
+ },
+ Remote {
+ #[serde(with = "hex")]
+ timeline_id: ZTimelineId,
+ #[serde(with = "hex")]
+ tenant_id: ZTenantId,
+ },
}
async fn timeline_detail_handler(request: Request) -> Result, ApiError> {
@@ -215,9 +224,12 @@ async fn timeline_detail_handler(request: Request) -> Result bail!("Timeline with id {} is not present locally", timeline_id),
- Some(timeline) => Ok::<_, anyhow::Error>(TimelineInfo {
+ Ok::<_, anyhow::Error>(match repo.get_timeline(timeline_id)?.local_timeline() {
+ None => TimelineInfo::Remote {
+ timeline_id,
+ tenant_id,
+ },
+ Some(timeline) => TimelineInfo::Local {
timeline_id,
tenant_id,
ancestor_timeline_id: timeline.get_ancestor_timeline_id(),
@@ -226,8 +238,8 @@ async fn timeline_detail_handler(request: Request) -> Result 0
+ for timeline_id_str in timelines:
+ timeline_details = client.timeline_details(tenant_id.hex, timeline_id_str)
+ assert timeline_details['type'] == 'Local'
+ assert timeline_details['tenant_id'] == tenant_id.hex
+ assert timeline_details['timeline_id'] == timeline_id_str
+
# create branch
branch_name = uuid4().hex
client.branch_create(tenant_id, branch_name, "main")
diff --git a/test_runner/fixtures/zenith_fixtures.py b/test_runner/fixtures/zenith_fixtures.py
index f7665c89d8..dfdf5c071b 100644
--- a/test_runner/fixtures/zenith_fixtures.py
+++ b/test_runner/fixtures/zenith_fixtures.py
@@ -671,6 +671,21 @@ class ZenithPageserverHttpClient(requests.Session):
res.raise_for_status()
return res.json()
+ def timeline_list(self, tenant_id: uuid.UUID) -> List[str]:
+ res = self.get(f"http://localhost:{self.port}/v1/timeline/{tenant_id.hex}")
+ res.raise_for_status()
+ res_json = res.json()
+ assert isinstance(res_json, list)
+ return res_json
+
+ def timeline_details(self, tenant_id: uuid.UUID, timeline_id: str) -> Dict[Any, Any]:
+ res = self.get(
+ f"http://localhost:{self.port}/v1/timeline/{tenant_id.hex}/{timeline_id}")
+ res.raise_for_status()
+ res_json = res.json()
+ assert isinstance(res_json, dict)
+ return res_json
+
def get_metrics(self) -> str:
res = self.get(f"http://localhost:{self.port}/metrics")
res.raise_for_status()