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