security_client_rs/fleet/
actions.rs1use serde::{Deserialize, Serialize};
3use serde_json::{Map, Value, json};
4
5use super::{Fleet, Items};
6use crate::{
7 Scope,
8 http::{Method, Raw},
9 request::endpoint,
10};
11
12#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
15#[serde(from = "String", into = "String")]
16#[non_exhaustive]
17pub enum ActionStatus {
18 InProgress,
19 Complete,
20 Failed,
21 Cancelled,
22 Expired,
23 RolloutPassed,
24 Unknown(String),
25}
26
27impl ActionStatus {
28 pub fn as_str(&self) -> &str {
30 match self {
31 Self::InProgress => "IN_PROGRESS",
32 Self::Complete => "COMPLETE",
33 Self::Failed => "FAILED",
34 Self::Cancelled => "CANCELLED",
35 Self::Expired => "EXPIRED",
36 Self::RolloutPassed => "ROLLOUT_PASSED",
37 Self::Unknown(status) => status,
38 }
39 }
40
41 pub fn is_finished(&self) -> bool {
57 !matches!(self, Self::InProgress)
58 }
59}
60
61impl From<String> for ActionStatus {
62 fn from(status: String) -> Self {
63 match status.as_str() {
64 "IN_PROGRESS" => Self::InProgress,
65 "COMPLETE" => Self::Complete,
66 "FAILED" => Self::Failed,
67 "CANCELLED" => Self::Cancelled,
68 "EXPIRED" => Self::Expired,
69 "ROLLOUT_PASSED" => Self::RolloutPassed,
70 _ => Self::Unknown(status),
71 }
72 }
73}
74
75impl From<ActionStatus> for String {
76 fn from(status: ActionStatus) -> Self {
77 match status {
78 ActionStatus::Unknown(status) => status,
79 known => known.as_str().to_owned(),
80 }
81 }
82}
83
84#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
87#[serde(from = "String", into = "String")]
88#[non_exhaustive]
89pub enum UploadStatus {
90 AwaitingUpload,
91 InProgress,
92 Ready,
94 Failed,
95 Expired,
96 Deleted,
97 Unknown(String),
98}
99
100impl UploadStatus {
101 pub fn as_str(&self) -> &str {
103 match self {
104 Self::AwaitingUpload => "AWAITING_UPLOAD",
105 Self::InProgress => "IN_PROGRESS",
106 Self::Ready => "READY",
107 Self::Failed => "FAILED",
108 Self::Expired => "EXPIRED",
109 Self::Deleted => "DELETED",
110 Self::Unknown(status) => status,
111 }
112 }
113
114 pub fn is_finished(&self) -> bool {
117 !matches!(self, Self::AwaitingUpload | Self::InProgress)
118 }
119}
120
121impl From<String> for UploadStatus {
122 fn from(status: String) -> Self {
123 match status.as_str() {
124 "AWAITING_UPLOAD" => Self::AwaitingUpload,
125 "IN_PROGRESS" => Self::InProgress,
126 "READY" => Self::Ready,
127 "FAILED" => Self::Failed,
128 "EXPIRED" => Self::Expired,
129 "DELETED" => Self::Deleted,
130 _ => Self::Unknown(status),
131 }
132 }
133}
134
135impl From<UploadStatus> for String {
136 fn from(status: UploadStatus) -> Self {
137 match status {
138 UploadStatus::Unknown(status) => status,
139 known => known.as_str().to_owned(),
140 }
141 }
142}
143
144#[derive(Clone, Debug, Deserialize, Serialize)]
146#[serde(rename_all = "camelCase")]
147#[non_exhaustive]
148pub struct AgentActionStatus {
149 pub action_id: String,
150 pub status: ActionStatus,
151 #[serde(rename = "type")]
152 pub action_type: String,
153 pub nb_agents_action_created: u64,
154 pub nb_agents_ack: u64,
155 pub nb_agents_failed: u64,
156 pub nb_agents_actioned: u64,
157 #[serde(default)]
158 pub latest_errors: Vec<Value>,
159 #[serde(flatten)]
160 pub extra: Map<String, Value>,
161}
162
163impl AgentActionStatus {
164 pub fn is_finished(&self) -> bool {
166 self.status.is_finished()
167 }
168}
169
170#[derive(Clone, Debug, Deserialize, Serialize)]
171#[serde(rename_all = "camelCase")]
172#[non_exhaustive]
173pub struct AgentUpload {
174 pub id: String,
175 pub name: String,
176 pub action_id: String,
177 pub status: UploadStatus,
178 #[serde(default)]
179 pub error: Option<String>,
180 #[serde(flatten)]
181 pub extra: Map<String, Value>,
182}
183
184impl AgentUpload {
185 pub fn is_finished(&self) -> bool {
187 self.status.is_finished()
188 }
189}
190
191impl<'a> Fleet<'a> {
192 pub fn agent_action_status(&self) -> AgentActionStatuses<'a> {
196 AgentActionStatuses(self.0.request(
197 Method::GET,
198 Scope::Space,
199 &["api", "fleet", "agents", "action_status"],
200 ))
201 }
202
203 pub fn cancel_agent_action(&self, action_id: &str) -> CancelAgentAction<'a> {
205 CancelAgentAction(
206 self.0
207 .request(
208 Method::POST,
209 Scope::Space,
210 &["api", "fleet", "agents", "actions", action_id, "cancel"],
211 )
212 .json(&json!({})),
213 )
214 }
215
216 pub fn list_agent_uploads(&self, agent_id: &str) -> ListAgentUploads<'a> {
217 ListAgentUploads(self.0.request(
218 Method::GET,
219 Scope::Space,
220 &["api", "fleet", "agents", agent_id, "uploads"],
221 ))
222 }
223
224 pub fn download_agent_file(&self, file_id: &str, file_name: &str) -> DownloadAgentFile<'a> {
227 DownloadAgentFile(self.0.request(
228 Method::GET,
229 Scope::Space,
230 &["api", "fleet", "agents", "files", file_id, file_name],
231 ))
232 }
233}
234
235endpoint! {
236 AgentActionStatuses => Items<AgentActionStatus>
238}
239
240impl AgentActionStatuses<'_> {
241 pub fn page(self, page: u32) -> Self {
243 Self(self.0.param("page", page))
244 }
245
246 pub fn per_page(self, per_page: u32) -> Self {
247 Self(self.0.positive_param("perPage", per_page))
248 }
249
250 pub fn date(self, date: &str) -> Self {
252 Self(self.0.param("date", date))
253 }
254
255 pub fn latest(self, seconds: u32) -> Self {
257 Self(self.0.param("latest", seconds))
258 }
259
260 pub fn error_size(self, size: u32) -> Self {
262 Self(self.0.param("errorSize", size))
263 }
264}
265
266endpoint! {
267 CancelAgentAction => Value
269}
270
271endpoint! {
272 ListAgentUploads => Items<AgentUpload>
274}
275
276endpoint! {
277 DownloadAgentFile => Raw
279}