Line data Source code
1 : use safekeeper_api::models::{
2 : self, PullTimelineRequest, PullTimelineResponse, SafekeeperUtilization, TimelineCreateRequest,
3 : };
4 : use safekeeper_client::mgmt_api::{Client, Result};
5 : use utils::id::{NodeId, TenantId, TimelineId};
6 : use utils::logging::SecretString;
7 :
8 : use crate::metrics::SafekeeperRequestLabelGroup;
9 :
10 : /// Thin wrapper around [`safekeeper_client::mgmt_api::Client`]. It allows the storage
11 : /// controller to collect metrics in a non-intrusive manner.
12 : ///
13 : /// Analogous to [`crate::pageserver_client::PageserverClient`].
14 : #[derive(Debug, Clone)]
15 : pub(crate) struct SafekeeperClient {
16 : inner: Client,
17 : node_id_label: String,
18 : }
19 :
20 : macro_rules! measured_request {
21 : ($name:literal, $method:expr, $node_id: expr, $invoke:expr) => {{
22 : let labels = SafekeeperRequestLabelGroup {
23 : safekeeper_id: $node_id,
24 : path: $name,
25 : method: $method,
26 : };
27 :
28 : let latency = &crate::metrics::METRICS_REGISTRY
29 : .metrics_group
30 : .storage_controller_safekeeper_request_latency;
31 : let _timer_guard = latency.start_timer(labels.clone());
32 :
33 : let res = $invoke;
34 :
35 : if res.is_err() {
36 : let error_counters = &crate::metrics::METRICS_REGISTRY
37 : .metrics_group
38 : .storage_controller_safekeeper_request_error;
39 : error_counters.inc(labels)
40 : }
41 :
42 : res
43 : }};
44 : }
45 :
46 : impl SafekeeperClient {
47 0 : pub(crate) fn new(
48 0 : node_id: NodeId,
49 0 : raw_client: reqwest::Client,
50 0 : mgmt_api_endpoint: String,
51 0 : jwt: Option<SecretString>,
52 0 : ) -> Self {
53 0 : Self {
54 0 : inner: Client::new(raw_client, mgmt_api_endpoint, jwt),
55 0 : node_id_label: node_id.0.to_string(),
56 0 : }
57 0 : }
58 :
59 0 : pub(crate) fn node_id_label(&self) -> &str {
60 0 : &self.node_id_label
61 0 : }
62 :
63 0 : pub(crate) async fn create_timeline(
64 0 : &self,
65 0 : req: &TimelineCreateRequest,
66 0 : ) -> Result<reqwest::Response> {
67 0 : measured_request!(
68 0 : "create_timeline",
69 0 : crate::metrics::Method::Post,
70 0 : &self.node_id_label,
71 0 : self.inner.create_timeline(req).await
72 : )
73 0 : }
74 :
75 : #[allow(unused)]
76 0 : pub(crate) async fn exclude_timeline(
77 0 : &self,
78 0 : tenant_id: TenantId,
79 0 : timeline_id: TimelineId,
80 0 : req: &models::TimelineMembershipSwitchRequest,
81 0 : ) -> Result<models::TimelineDeleteResult> {
82 0 : measured_request!(
83 0 : "exclude_timeline",
84 0 : crate::metrics::Method::Post,
85 0 : &self.node_id_label,
86 0 : self.inner
87 0 : .exclude_timeline(tenant_id, timeline_id, req)
88 0 : .await
89 : )
90 0 : }
91 :
92 0 : pub(crate) async fn delete_timeline(
93 0 : &self,
94 0 : tenant_id: TenantId,
95 0 : timeline_id: TimelineId,
96 0 : ) -> Result<models::TimelineDeleteResult> {
97 0 : measured_request!(
98 0 : "delete_timeline",
99 0 : crate::metrics::Method::Delete,
100 0 : &self.node_id_label,
101 0 : self.inner.delete_timeline(tenant_id, timeline_id).await
102 : )
103 0 : }
104 :
105 : #[allow(unused)]
106 0 : pub(crate) async fn switch_timeline_membership(
107 0 : &self,
108 0 : tenant_id: TenantId,
109 0 : timeline_id: TimelineId,
110 0 : req: &models::TimelineMembershipSwitchRequest,
111 0 : ) -> Result<models::TimelineMembershipSwitchResponse> {
112 0 : measured_request!(
113 0 : "switch_timeline_membership",
114 0 : crate::metrics::Method::Put,
115 0 : &self.node_id_label,
116 0 : self.inner
117 0 : .switch_timeline_membership(tenant_id, timeline_id, req)
118 0 : .await
119 : )
120 0 : }
121 :
122 0 : pub(crate) async fn delete_tenant(
123 0 : &self,
124 0 : tenant_id: TenantId,
125 0 : ) -> Result<models::TenantDeleteResult> {
126 0 : measured_request!(
127 0 : "delete_tenant",
128 0 : crate::metrics::Method::Delete,
129 0 : &self.node_id_label,
130 0 : self.inner.delete_tenant(tenant_id).await
131 : )
132 0 : }
133 :
134 0 : pub(crate) async fn pull_timeline(
135 0 : &self,
136 0 : req: &PullTimelineRequest,
137 0 : ) -> Result<PullTimelineResponse> {
138 0 : measured_request!(
139 0 : "pull_timeline",
140 0 : crate::metrics::Method::Post,
141 0 : &self.node_id_label,
142 0 : self.inner.pull_timeline(req).await
143 : )
144 0 : }
145 :
146 : #[allow(unused)]
147 0 : pub(crate) async fn bump_timeline_term(
148 0 : &self,
149 0 : tenant_id: TenantId,
150 0 : timeline_id: TimelineId,
151 0 : req: &models::TimelineTermBumpRequest,
152 0 : ) -> Result<models::TimelineTermBumpResponse> {
153 0 : measured_request!(
154 0 : "term_bump",
155 0 : crate::metrics::Method::Post,
156 0 : &self.node_id_label,
157 0 : self.inner
158 0 : .bump_timeline_term(tenant_id, timeline_id, req)
159 0 : .await
160 : )
161 0 : }
162 :
163 0 : pub(crate) async fn get_utilization(&self) -> Result<SafekeeperUtilization> {
164 0 : measured_request!(
165 0 : "utilization",
166 0 : crate::metrics::Method::Get,
167 0 : &self.node_id_label,
168 0 : self.inner.utilization().await
169 : )
170 0 : }
171 : }
|