Line data Source code
1 : use hyper::{Body, Request, Response, StatusCode};
2 : use serde::{Deserialize, Serialize};
3 : use tokio_util::sync::CancellationToken;
4 : use utils::failpoint_support::apply_failpoint;
5 :
6 : use crate::error::ApiError;
7 : use crate::json::{json_request, json_response};
8 :
9 : pub type ConfigureFailpointsRequest = Vec<FailpointConfig>;
10 :
11 : /// Information for configuring a single fail point
12 0 : #[derive(Debug, Serialize, Deserialize)]
13 : pub struct FailpointConfig {
14 : /// Name of the fail point
15 : pub name: String,
16 : /// List of actions to take, using the format described in `fail::cfg`
17 : ///
18 : /// We also support `actions = "exit"` to cause the fail point to immediately exit.
19 : pub actions: String,
20 : }
21 :
22 : /// Configure failpoints through http.
23 0 : pub async fn failpoints_handler(
24 0 : mut request: Request<Body>,
25 0 : _cancel: CancellationToken,
26 0 : ) -> Result<Response<Body>, ApiError> {
27 0 : if !fail::has_failpoints() {
28 0 : return Err(ApiError::BadRequest(anyhow::anyhow!(
29 0 : "Cannot manage failpoints because neon was compiled without failpoints support"
30 0 : )));
31 0 : }
32 :
33 0 : let failpoints: ConfigureFailpointsRequest = json_request(&mut request).await?;
34 0 : for fp in failpoints {
35 0 : tracing::info!("cfg failpoint: {} {}", fp.name, fp.actions);
36 :
37 : // We recognize one extra "action" that's not natively recognized
38 : // by the failpoints crate: exit, to immediately kill the process
39 0 : let cfg_result = apply_failpoint(&fp.name, &fp.actions);
40 :
41 0 : if let Err(err_msg) = cfg_result {
42 0 : return Err(ApiError::BadRequest(anyhow::anyhow!(
43 0 : "Failed to configure failpoints: {err_msg}"
44 0 : )));
45 0 : }
46 : }
47 :
48 0 : json_response(StatusCode::OK, ())
49 0 : }
|