meta_srv/service/admin/
maintenance.rs1use std::collections::HashMap;
16
17use common_meta::key::maintenance::MaintenanceModeManagerRef;
18use common_telemetry::{info, warn};
19use serde::{Deserialize, Serialize};
20use snafu::{OptionExt, ResultExt};
21use tonic::codegen::http;
22use tonic::codegen::http::Response;
23
24use crate::error::{
25 self, InvalidHttpBodySnafu, MaintenanceModeManagerSnafu, MissingRequiredParameterSnafu,
26 ParseBoolSnafu, Result, UnsupportedSnafu,
27};
28use crate::service::admin::HttpHandler;
29
30#[derive(Clone)]
31pub struct MaintenanceHandler {
32 pub manager: MaintenanceModeManagerRef,
33}
34
35#[derive(Debug, Serialize, Deserialize)]
36struct MaintenanceResponse {
37 enabled: bool,
38}
39
40impl TryFrom<MaintenanceResponse> for String {
41 type Error = error::Error;
42
43 fn try_from(response: MaintenanceResponse) -> Result<Self> {
44 serde_json::to_string(&response).context(error::SerializeToJsonSnafu {
45 input: format!("{response:?}"),
46 })
47 }
48}
49
50impl MaintenanceHandler {
51 async fn get_maintenance(&self) -> crate::Result<Response<String>> {
52 let enabled = self
53 .manager
54 .maintenance_mode()
55 .await
56 .context(MaintenanceModeManagerSnafu)?;
57 let response = MaintenanceResponse { enabled }.try_into()?;
58 http::Response::builder()
59 .status(http::StatusCode::OK)
60 .body(response)
61 .context(InvalidHttpBodySnafu)
62 }
63
64 async fn set_maintenance(
65 &self,
66 params: &HashMap<String, String>,
67 ) -> crate::Result<Response<String>> {
68 let enable = params
69 .get("enable")
70 .map(|v| v.parse::<bool>())
71 .context(MissingRequiredParameterSnafu { param: "enable" })?
72 .context(ParseBoolSnafu {
73 err_msg: "'enable' must be 'true' or 'false'",
74 })?;
75
76 if enable {
77 self.manager
78 .set_maintenance_mode()
79 .await
80 .context(MaintenanceModeManagerSnafu)?;
81 info!("Enable the maintenance mode.");
82 } else {
83 self.manager
84 .unset_maintenance_mode()
85 .await
86 .context(MaintenanceModeManagerSnafu)?;
87 info!("Disable the maintenance mode.");
88 };
89
90 let response = MaintenanceResponse { enabled: enable }.try_into()?;
91 http::Response::builder()
92 .status(http::StatusCode::OK)
93 .body(response)
94 .context(InvalidHttpBodySnafu)
95 }
96}
97
98#[async_trait::async_trait]
99impl HttpHandler for MaintenanceHandler {
100 async fn handle(
101 &self,
102 _: &str,
103 method: http::Method,
104 params: &HashMap<String, String>,
105 ) -> crate::Result<Response<String>> {
106 match method {
107 http::Method::GET => {
108 if params.is_empty() {
109 self.get_maintenance().await
110 } else {
111 warn!(
112 "Found URL parameters in '/admin/maintenance' request, it's deprecated, will be removed in the future"
113 );
114 self.set_maintenance(params).await
117 }
118 }
119 http::Method::PUT => {
120 warn!("Found PUT request to '/admin/maintenance', it's deprecated, will be removed in the future");
121 self.set_maintenance(params).await
122 }
123 http::Method::POST => self.set_maintenance(params).await,
124 _ => UnsupportedSnafu {
125 operation: format!("http method {method}"),
126 }
127 .fail(),
128 }
129 }
130}