Line data Source code
1 : use pageserver_api::{
2 : models::{
3 : LocationConfig, LocationConfigListResponse, PageserverUtilization, SecondaryProgress,
4 : TenantScanRemoteStorageResponse, TenantShardSplitRequest, TenantShardSplitResponse,
5 : TimelineCreateRequest, TimelineInfo,
6 : },
7 : shard::TenantShardId,
8 : };
9 : use pageserver_client::mgmt_api::{Client, Result};
10 : use reqwest::StatusCode;
11 : use utils::id::{NodeId, TenantId, TimelineId};
12 :
13 : /// Thin wrapper around [`pageserver_client::mgmt_api::Client`]. It allows the storage
14 : /// controller to collect metrics in a non-intrusive manner.
15 : #[derive(Debug, Clone)]
16 : pub(crate) struct PageserverClient {
17 : inner: Client,
18 : node_id_label: String,
19 : }
20 :
21 : macro_rules! measured_request {
22 : ($name:literal, $method:expr, $node_id: expr, $invoke:expr) => {{
23 : let labels = crate::metrics::PageserverRequestLabelGroup {
24 : pageserver_id: $node_id,
25 : path: $name,
26 : method: $method,
27 : };
28 :
29 : let latency = &crate::metrics::METRICS_REGISTRY
30 : .metrics_group
31 : .storage_controller_pageserver_request_latency;
32 : let _timer_guard = latency.start_timer(labels.clone());
33 :
34 : let res = $invoke;
35 :
36 : if res.is_err() {
37 : let error_counters = &crate::metrics::METRICS_REGISTRY
38 : .metrics_group
39 : .storage_controller_pageserver_request_error;
40 : error_counters.inc(labels)
41 : }
42 :
43 : res
44 : }};
45 : }
46 :
47 : impl PageserverClient {
48 0 : pub(crate) fn new(node_id: NodeId, mgmt_api_endpoint: String, jwt: Option<&str>) -> Self {
49 0 : Self {
50 0 : inner: Client::from_client(reqwest::Client::new(), mgmt_api_endpoint, jwt),
51 0 : node_id_label: node_id.0.to_string(),
52 0 : }
53 0 : }
54 :
55 0 : pub(crate) fn from_client(
56 0 : node_id: NodeId,
57 0 : raw_client: reqwest::Client,
58 0 : mgmt_api_endpoint: String,
59 0 : jwt: Option<&str>,
60 0 : ) -> Self {
61 0 : Self {
62 0 : inner: Client::from_client(raw_client, mgmt_api_endpoint, jwt),
63 0 : node_id_label: node_id.0.to_string(),
64 0 : }
65 0 : }
66 :
67 0 : pub(crate) async fn tenant_delete(&self, tenant_shard_id: TenantShardId) -> Result<StatusCode> {
68 0 : measured_request!(
69 0 : "tenant",
70 0 : crate::metrics::Method::Delete,
71 0 : &self.node_id_label,
72 0 : self.inner.tenant_delete(tenant_shard_id).await
73 : )
74 0 : }
75 :
76 0 : pub(crate) async fn tenant_time_travel_remote_storage(
77 0 : &self,
78 0 : tenant_shard_id: TenantShardId,
79 0 : timestamp: &str,
80 0 : done_if_after: &str,
81 0 : ) -> Result<()> {
82 0 : measured_request!(
83 0 : "tenant_time_travel_remote_storage",
84 0 : crate::metrics::Method::Put,
85 0 : &self.node_id_label,
86 0 : self.inner
87 0 : .tenant_time_travel_remote_storage(tenant_shard_id, timestamp, done_if_after)
88 0 : .await
89 : )
90 0 : }
91 :
92 0 : pub(crate) async fn tenant_scan_remote_storage(
93 0 : &self,
94 0 : tenant_id: TenantId,
95 0 : ) -> Result<TenantScanRemoteStorageResponse> {
96 0 : measured_request!(
97 0 : "tenant_scan_remote_storage",
98 0 : crate::metrics::Method::Get,
99 0 : &self.node_id_label,
100 0 : self.inner.tenant_scan_remote_storage(tenant_id).await
101 : )
102 0 : }
103 :
104 0 : pub(crate) async fn tenant_secondary_download(
105 0 : &self,
106 0 : tenant_id: TenantShardId,
107 0 : wait: Option<std::time::Duration>,
108 0 : ) -> Result<(StatusCode, SecondaryProgress)> {
109 0 : measured_request!(
110 0 : "tenant_secondary_download",
111 0 : crate::metrics::Method::Post,
112 0 : &self.node_id_label,
113 0 : self.inner.tenant_secondary_download(tenant_id, wait).await
114 : )
115 0 : }
116 :
117 0 : pub(crate) async fn tenant_secondary_status(
118 0 : &self,
119 0 : tenant_shard_id: TenantShardId,
120 0 : ) -> Result<SecondaryProgress> {
121 0 : measured_request!(
122 0 : "tenant_secondary_status",
123 0 : crate::metrics::Method::Get,
124 0 : &self.node_id_label,
125 0 : self.inner.tenant_secondary_status(tenant_shard_id).await
126 : )
127 0 : }
128 :
129 0 : pub(crate) async fn tenant_heatmap_upload(&self, tenant_id: TenantShardId) -> Result<()> {
130 0 : measured_request!(
131 0 : "tenant_heatmap_upload",
132 0 : crate::metrics::Method::Post,
133 0 : &self.node_id_label,
134 0 : self.inner.tenant_heatmap_upload(tenant_id).await
135 : )
136 0 : }
137 :
138 0 : pub(crate) async fn location_config(
139 0 : &self,
140 0 : tenant_shard_id: TenantShardId,
141 0 : config: LocationConfig,
142 0 : flush_ms: Option<std::time::Duration>,
143 0 : lazy: bool,
144 0 : ) -> Result<()> {
145 0 : measured_request!(
146 0 : "location_config",
147 0 : crate::metrics::Method::Put,
148 0 : &self.node_id_label,
149 0 : self.inner
150 0 : .location_config(tenant_shard_id, config, flush_ms, lazy)
151 0 : .await
152 : )
153 0 : }
154 :
155 0 : pub(crate) async fn list_location_config(&self) -> Result<LocationConfigListResponse> {
156 0 : measured_request!(
157 0 : "location_configs",
158 0 : crate::metrics::Method::Get,
159 0 : &self.node_id_label,
160 0 : self.inner.list_location_config().await
161 : )
162 0 : }
163 :
164 0 : pub(crate) async fn get_location_config(
165 0 : &self,
166 0 : tenant_shard_id: TenantShardId,
167 0 : ) -> Result<Option<LocationConfig>> {
168 0 : measured_request!(
169 0 : "location_config",
170 0 : crate::metrics::Method::Get,
171 0 : &self.node_id_label,
172 0 : self.inner.get_location_config(tenant_shard_id).await
173 : )
174 0 : }
175 :
176 0 : pub(crate) async fn timeline_create(
177 0 : &self,
178 0 : tenant_shard_id: TenantShardId,
179 0 : req: &TimelineCreateRequest,
180 0 : ) -> Result<TimelineInfo> {
181 0 : measured_request!(
182 0 : "timeline",
183 0 : crate::metrics::Method::Post,
184 0 : &self.node_id_label,
185 0 : self.inner.timeline_create(tenant_shard_id, req).await
186 : )
187 0 : }
188 :
189 0 : pub(crate) async fn timeline_delete(
190 0 : &self,
191 0 : tenant_shard_id: TenantShardId,
192 0 : timeline_id: TimelineId,
193 0 : ) -> Result<StatusCode> {
194 0 : measured_request!(
195 0 : "timeline",
196 0 : crate::metrics::Method::Delete,
197 0 : &self.node_id_label,
198 0 : self.inner
199 0 : .timeline_delete(tenant_shard_id, timeline_id)
200 0 : .await
201 : )
202 0 : }
203 :
204 0 : pub(crate) async fn tenant_shard_split(
205 0 : &self,
206 0 : tenant_shard_id: TenantShardId,
207 0 : req: TenantShardSplitRequest,
208 0 : ) -> Result<TenantShardSplitResponse> {
209 0 : measured_request!(
210 0 : "tenant_shard_split",
211 0 : crate::metrics::Method::Put,
212 0 : &self.node_id_label,
213 0 : self.inner.tenant_shard_split(tenant_shard_id, req).await
214 : )
215 0 : }
216 :
217 0 : pub(crate) async fn timeline_list(
218 0 : &self,
219 0 : tenant_shard_id: &TenantShardId,
220 0 : ) -> Result<Vec<TimelineInfo>> {
221 0 : measured_request!(
222 0 : "timelines",
223 0 : crate::metrics::Method::Get,
224 0 : &self.node_id_label,
225 0 : self.inner.timeline_list(tenant_shard_id).await
226 : )
227 0 : }
228 :
229 0 : pub(crate) async fn get_utilization(&self) -> Result<PageserverUtilization> {
230 0 : measured_request!(
231 0 : "utilization",
232 0 : crate::metrics::Method::Get,
233 0 : &self.node_id_label,
234 0 : self.inner.get_utilization().await
235 : )
236 0 : }
237 : }
|