From 8368ea6661e8f8a74eb138275a39d70c8009e232 Mon Sep 17 00:00:00 2001 From: Christian Schwarz Date: Wed, 13 Dec 2023 14:03:12 +0000 Subject: [PATCH] include timeline ids in tenant details response --- libs/pageserver_api/src/models.rs | 8 ++++++++ pageserver/src/client/mgmt_api.rs | 13 +++++++++++++ pageserver/src/http/routes.rs | 16 ++++++++++------ pageserver/src/tenant.rs | 4 ++++ 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/libs/pageserver_api/src/models.rs b/libs/pageserver_api/src/models.rs index 8adb581707..c1c1917da5 100644 --- a/libs/pageserver_api/src/models.rs +++ b/libs/pageserver_api/src/models.rs @@ -375,6 +375,14 @@ pub struct TenantInfo { pub generation: Option, } +#[derive(Serialize, Deserialize, Clone)] +pub struct TenantDetails { + #[serde(flatten)] + pub tenant_info: TenantInfo, + + pub timelines: Vec, +} + /// This represents the output of the "timeline_detail" and "timeline_list" API calls. #[derive(Debug, Serialize, Deserialize, Clone)] pub struct TimelineInfo { diff --git a/pageserver/src/client/mgmt_api.rs b/pageserver/src/client/mgmt_api.rs index 07f4213e7f..5dd9fb08ae 100644 --- a/pageserver/src/client/mgmt_api.rs +++ b/pageserver/src/client/mgmt_api.rs @@ -28,6 +28,19 @@ impl Client { Ok(serde_json::from_slice(&body)?) } + pub async fn tenant_details( + &self, + tenant_id: TenantId, + ) -> anyhow::Result { + let uri = Uri::try_from(format!("{}/v1/tenant/{tenant_id}", self.mgmt_api_endpoint))?; + let resp = self.get(uri).await?; + if !resp.status().is_success() { + anyhow::bail!("status error"); + } + let body = hyper::body::to_bytes(resp).await?; + Ok(serde_json::from_slice(&body)?) + } + pub async fn list_timelines( &self, tenant_id: TenantId, diff --git a/pageserver/src/http/routes.rs b/pageserver/src/http/routes.rs index bc839f8aba..759df34d7e 100644 --- a/pageserver/src/http/routes.rs +++ b/pageserver/src/http/routes.rs @@ -12,6 +12,7 @@ use hyper::header; use hyper::StatusCode; use hyper::{Body, Request, Response, Uri}; use metrics::launch_timestamp::LaunchTimestamp; +use pageserver_api::models::TenantDetails; use pageserver_api::models::{ DownloadRemoteLayersTaskSpawnRequest, LocationConfigMode, TenantAttachRequest, TenantLoadRequest, TenantLocationConfigRequest, @@ -793,12 +794,15 @@ async fn tenant_status( } let state = tenant.current_state(); - Result::<_, ApiError>::Ok(TenantInfo { - id: tenant_id, - state: state.clone(), - current_physical_size: Some(current_physical_size), - attachment_status: state.attachment_status(), - generation: tenant.generation().into(), + Result::<_, ApiError>::Ok(TenantDetails { + tenant_info: TenantInfo { + id: tenant_id, + state: state.clone(), + current_physical_size: Some(current_physical_size), + attachment_status: state.attachment_status(), + generation: tenant.generation().into(), + }, + timelines: tenant.list_timeline_ids(), }) } .instrument(info_span!("tenant_status_handler", %tenant_id)) diff --git a/pageserver/src/tenant.rs b/pageserver/src/tenant.rs index 3da2d0d473..ba4c4e72f3 100644 --- a/pageserver/src/tenant.rs +++ b/pageserver/src/tenant.rs @@ -1404,6 +1404,10 @@ impl Tenant { .collect() } + pub fn list_timeline_ids(&self) -> Vec { + self.timelines.lock().unwrap().keys().cloned().collect() + } + /// This is used to create the initial 'main' timeline during bootstrapping, /// or when importing a new base backup. The caller is expected to load an /// initial image of the datadir to the new timeline after this.