sui_security_watchdog/
pagerduty.rs1use anyhow::anyhow;
5use serde::{Deserialize, Serialize};
6use std::sync::Arc;
7use tracing::info;
8
9#[derive(Serialize, Deserialize, Debug)]
10pub struct Service {
11 pub id: String,
12 #[serde(rename = "type")]
13 pub r#type: String,
14}
15
16impl Default for Service {
17 fn default() -> Self {
18 Service {
19 id: "".to_string(),
20 r#type: "service_reference".to_string(),
21 }
22 }
23}
24
25#[derive(Serialize, Deserialize, Debug)]
26pub struct Body {
27 #[serde(rename = "type")]
28 pub r#type: String,
29 pub details: String,
30}
31
32impl Default for Body {
33 fn default() -> Self {
34 Body {
35 r#type: "incident_body".to_string(),
36 details: "".to_string(),
37 }
38 }
39}
40
41#[derive(Serialize, Deserialize, Debug)]
42pub struct Incident {
43 pub incident_key: String,
44 #[serde(rename = "type")]
45 pub r#type: String,
46 pub title: String,
47 pub service: Service,
48 pub body: Body,
49}
50
51impl Default for Incident {
52 fn default() -> Self {
53 Incident {
54 incident_key: "".to_string(),
55 r#type: "incident".to_string(),
56 title: "".to_string(),
57 service: Service::default(),
58 body: Body::default(),
59 }
60 }
61}
62
63#[derive(Serialize, Deserialize)]
64pub struct CreateIncident {
65 pub incident: Incident,
66}
67
68#[derive(Clone)]
69pub struct Pagerduty {
70 pub client: Arc<reqwest::Client>,
71 pub api_key: String,
72}
73
74impl Pagerduty {
75 pub fn new(api_key: String) -> Self {
76 Pagerduty {
77 client: Arc::new(reqwest::Client::new()),
78 api_key,
79 }
80 }
81
82 pub async fn create_incident(
83 &self,
84 from: &str,
85 incident: CreateIncident,
86 ) -> anyhow::Result<()> {
87 let token = format!("Token token={}", self.api_key);
88
89 let response = self
90 .client
91 .post("https://api.pagerduty.com/incidents")
92 .header("Authorization", token)
93 .header("Content-Type", "application/json")
94 .header("Accept", "application/json")
95 .header("From", from)
96 .json(&incident)
97 .send()
98 .await?;
99 if response.status().is_success() {
101 info!(
102 "Created incident with key: {:?}",
103 incident.incident.incident_key
104 );
105 Ok(())
106 } else {
107 let status = response.status();
108 let text = response.text().await?;
109 if status.is_client_error()
110 && text.contains(
111 "Open incident with matching dedup key already exists on this service",
112 )
113 {
114 info!(
115 "Incident already exists with key: {}",
116 incident.incident.incident_key
117 );
118 Ok(())
119 } else {
120 Err(anyhow!("Failed to create incident: {}", text))
121 }
122 }
123 }
124}