diff --git a/libs/safekeeper_api/src/models.rs b/libs/safekeeper_api/src/models.rs index 7d473e8934..73ad7f5842 100644 --- a/libs/safekeeper_api/src/models.rs +++ b/libs/safekeeper_api/src/models.rs @@ -10,6 +10,7 @@ use utils::generation::Generation; use utils::id::{NodeId, TenantId, TenantTimelineId, TimelineId}; use utils::lsn::Lsn; use utils::pageserver_feedback::PageserverFeedback; +use utils::shard::{ShardIndex, TenantShardId}; use crate::membership::Configuration; use crate::{ServerInfo, Term}; @@ -320,6 +321,7 @@ pub enum TenantShardPageserverAttachmentChange { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct TenantShardPageserverAttachment { - pub ps_id: NodeId, + pub shard: ShardIndex, pub generation: Generation, + pub ps_id: NodeId, } diff --git a/safekeeper/client/src/mgmt_api.rs b/safekeeper/client/src/mgmt_api.rs index 8068b9bb4d..e5e290fa6e 100644 --- a/safekeeper/client/src/mgmt_api.rs +++ b/safekeeper/client/src/mgmt_api.rs @@ -196,7 +196,8 @@ impl Client { body: TenantShardPageserverAttachmentChange, ) -> Result<()> { let uri = format!( - "{}/v1/tenant/{tenant_shard_id}/pageserver_attachments", + "{}/v1/tenant/{}/pageserver_attachments", + tenant_shard_id.tenant_id, self.mgmt_api_endpoint ); let resp = self.post(uri, body).await?; diff --git a/safekeeper/src/http/routes.rs b/safekeeper/src/http/routes.rs index 384c582678..337601c44a 100644 --- a/safekeeper/src/http/routes.rs +++ b/safekeeper/src/http/routes.rs @@ -18,8 +18,8 @@ use pem::Pem; use postgres_ffi::WAL_SEGMENT_SIZE; use safekeeper_api::models::{ AcceptorStateStatus, PullTimelineRequest, SafekeeperStatus, SkTimelineInfo, TenantDeleteResult, - TermSwitchApiEntry, TimelineCopyRequest, TimelineCreateRequest, TimelineDeleteResult, - TimelineStatus, TimelineTermBumpRequest, + TenantShardPageserverAttachmentChange, TermSwitchApiEntry, TimelineCopyRequest, + TimelineCreateRequest, TimelineDeleteResult, TimelineStatus, TimelineTermBumpRequest, }; use safekeeper_api::{ServerInfo, membership, models}; use storage_broker::proto::{SafekeeperTimelineInfo, TenantTimelineId as ProtoTenantTimelineId}; @@ -67,6 +67,22 @@ fn check_permission(request: &Request, tenant_id: Option) -> Res }) } +async fn post_tenant_pageserver_attachments(mut request: Request) -> Result<(), ApiError> { + let tenant_id = parse_request_param(&request, "tenant_id")?; + check_permission(&request, Some(tenant_id))?; + let body: TenantShardPageserverAttachmentChange = json_request(&mut request).await?; + let global_timelines = get_global_timelines(&request); + + match body { + TenantShardPageserverAttachmentChange::Attach(tenant_shard_pageserver_attachment) => { + todo!() + } + TenantShardPageserverAttachmentChange::Detach(tenant_shard_pageserver_attachment) => { + todo!() + } + } +} + /// Deactivates all timelines for the tenant and removes its data directory. /// See `timeline_delete_handler`. async fn tenant_delete_handler(mut request: Request) -> Result, ApiError> { @@ -718,6 +734,9 @@ pub fn make_router( }) }) .get("/v1/utilization", |r| request_span(r, utilization_handler)) + .post("/v1/tenant/:tenant_id/pageserver_attachments", |r| { + request_span(r, post_tenant_pageserver_attachments) + }) .delete("/v1/tenant/:tenant_id", |r| { request_span(r, tenant_delete_handler) }) diff --git a/storage_controller/src/service/sk_ps_discovery.rs b/storage_controller/src/service/sk_ps_discovery.rs index 3f7f09588b..91c4a24d69 100644 --- a/storage_controller/src/service/sk_ps_discovery.rs +++ b/storage_controller/src/service/sk_ps_discovery.rs @@ -16,6 +16,7 @@ use utils::{ generation::Generation, id::{NodeId, TenantId}, logging::SecretString, + shard::ShardIndex, }; use crate::{ @@ -223,6 +224,10 @@ impl DeliveryAttempt { let body = { let val = TenantShardPageserverAttachment { + shard: ShardIndex { + shard_number: utils::shard::ShardNumber(self.work.shard_number as u8), + shard_count: utils::shard::ShardCount(self.work.shard_count as u8), + }, ps_id: NodeId(self.work.ps_id as u64), generation: Generation::new(self.work.ps_generation as u32), };