1use std::{collections::HashMap, str::FromStr};
2
3use chrono::{DateTime, Duration, Utc};
4use serde::{Deserialize, Serialize};
5use serde_json::Value;
6use utoipa::{IntoParams, ToSchema};
7use uuid::Uuid;
8use validator::{Validate, ValidationError};
9
10#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, ToSchema)]
11#[serde(rename_all = "snake_case")]
12pub enum AuthProvider {
13 Local,
14 OAuth { provider: String },
15}
16
17#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
18pub struct CreateUserRequest {
19 #[validate(length(min = 3, max = 32))]
20 pub username: String,
21 #[validate(email)]
22 pub email: String,
23 #[validate(length(min = 12, max = 128))]
24 pub password: String,
25 #[validate(length(max = 64))]
26 pub display_name: Option<String>,
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
30pub struct LoginRequest {
31 #[validate(length(min = 1, max = 320))]
32 pub username_or_email: String,
33 #[validate(length(min = 1, max = 128))]
34 pub password: String,
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
38pub struct RefreshTokenRequest {
39 #[validate(length(min = 32, max = 128))]
40 pub refresh_token: String,
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
44pub struct UpdateUserRequest {
45 #[validate(length(min = 1, max = 64))]
46 pub display_name: Option<String>,
47 #[validate(length(min = 1, max = 512))]
48 pub bio: Option<String>,
49}
50
51#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
52pub struct User {
53 pub id: Uuid,
54 pub username: String,
55 pub email: String,
56 #[serde(skip_serializing_if = "Option::is_none")]
57 pub display_name: Option<String>,
58 #[serde(skip_serializing_if = "Option::is_none")]
59 pub bio: Option<String>,
60 #[serde(default, skip_serializing)]
61 #[schema(ignore)]
62 pub roles: Vec<String>,
63 #[serde(default)]
64 pub groups: Vec<String>,
65 pub created_at: DateTime<Utc>,
66 pub updated_at: DateTime<Utc>,
67 #[serde(skip_serializing_if = "Option::is_none")]
68 pub last_login: Option<DateTime<Utc>>,
69 pub is_active: bool,
70 pub is_verified: bool,
71 pub provider: AuthProvider,
72}
73
74impl User {
75 #[must_use]
76 pub fn effective_roles(&self) -> &[String] {
77 if self.roles.is_empty() {
78 &self.groups
79 } else {
80 &self.roles
81 }
82 }
83
84 #[must_use]
85 pub fn has_role(&self, role: &str) -> bool {
86 self.effective_roles()
87 .iter()
88 .any(|value| value.eq_ignore_ascii_case(role))
89 }
90
91 #[must_use]
92 pub fn has_any_role(&self, roles: &[&str]) -> bool {
93 self.effective_roles()
94 .iter()
95 .any(|value| roles.iter().any(|role| value.eq_ignore_ascii_case(role)))
96 }
97}
98
99#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
100#[allow(clippy::struct_excessive_bools)]
101pub struct AdminUserSummary {
102 pub id: Uuid,
103 pub username: String,
104 pub email: String,
105 #[serde(skip_serializing_if = "Option::is_none")]
106 pub display_name: Option<String>,
107 #[serde(skip_serializing_if = "Option::is_none")]
108 pub bio: Option<String>,
109 #[serde(default, skip_serializing)]
110 #[schema(ignore)]
111 pub roles: Vec<String>,
112 #[serde(default)]
113 pub groups: Vec<String>,
114 pub created_at: DateTime<Utc>,
115 pub updated_at: DateTime<Utc>,
116 #[serde(skip_serializing_if = "Option::is_none")]
117 pub last_login: Option<DateTime<Utc>>,
118 pub is_active: bool,
119 pub is_verified: bool,
120 pub provider: AuthProvider,
121 pub is_admin: bool,
122 pub can_manage_api_keys: bool,
123}
124
125impl AdminUserSummary {
126 #[must_use]
127 pub fn from_user(user: &User) -> Self {
128 let is_admin = user.has_role("admin");
129 let can_manage_api_keys = user.has_role("api_admin");
130
131 Self {
132 id: user.id,
133 username: user.username.clone(),
134 email: user.email.clone(),
135 display_name: user.display_name.clone(),
136 bio: user.bio.clone(),
137 roles: user.effective_roles().to_vec(),
138 groups: user.effective_roles().to_vec(),
139 created_at: user.created_at,
140 updated_at: user.updated_at,
141 last_login: user.last_login,
142 is_active: user.is_active,
143 is_verified: user.is_verified,
144 provider: user.provider.clone(),
145 is_admin,
146 can_manage_api_keys,
147 }
148 }
149}
150
151#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
152pub struct AdminUserListResponse {
153 pub users: Vec<AdminUserSummary>,
154}
155
156#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
157pub struct UpdateUserAccessRequest {
158 pub is_admin: Option<bool>,
159 pub can_manage_api_keys: Option<bool>,
160}
161
162#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
163pub struct TokenResponse {
164 pub access_token: String,
165 pub refresh_token: String,
166 pub token_type: String,
167 pub expires_in: u64,
168}
169
170#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
171pub struct ProviderTokenResponse {
172 pub access_token: String,
173 pub token_type: String,
174 pub expires_in: u64,
175 #[serde(skip_serializing_if = "Option::is_none")]
176 pub refresh_token: Option<String>,
177 #[serde(skip_serializing_if = "Option::is_none")]
178 pub id_token: Option<String>,
179 #[serde(skip_serializing_if = "Option::is_none")]
180 pub scope: Option<String>,
181}
182
183#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, ToSchema)]
184#[serde(rename_all = "snake_case")]
185pub enum AgentStatus {
186 Online,
187 Offline,
188 Draining,
189}
190
191#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
192pub struct AgentInputCapability {
193 #[serde(default)]
194 pub keyboard: bool,
195 #[serde(default)]
196 pub mouse: bool,
197}
198
199#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
200pub struct ScreenCaptureCapability {
201 pub supported: bool,
202 #[serde(default, skip_serializing_if = "Vec::is_empty")]
203 pub formats: Vec<String>,
204}
205
206#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
207pub struct Capabilities {
208 #[serde(skip_serializing_if = "Option::is_none")]
209 pub os: Option<String>,
210 #[serde(default, skip_serializing_if = "Vec::is_empty")]
211 pub tasks: Vec<String>,
212 #[serde(skip_serializing_if = "Option::is_none")]
213 pub input: Option<AgentInputCapability>,
214 #[serde(skip_serializing_if = "Option::is_none")]
215 pub screen_capture: Option<ScreenCaptureCapability>,
216 #[serde(skip_serializing_if = "Option::is_none")]
217 pub max_concurrency: Option<u32>,
218 #[serde(skip_serializing_if = "Option::is_none")]
219 pub version: Option<String>,
220}
221
222#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
223pub struct CpuInfo {
224 #[serde(skip_serializing_if = "Option::is_none")]
225 pub model: Option<String>,
226 pub logical_cores: usize,
227 #[serde(skip_serializing_if = "Option::is_none")]
228 pub physical_cores: Option<usize>,
229 #[serde(skip_serializing_if = "Option::is_none")]
230 pub usage_percent: Option<f64>,
231}
232
233#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
234pub struct MemoryInfo {
235 pub total_bytes: u64,
236 pub available_bytes: u64,
237}
238
239#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
240pub struct GpuInfo {
241 pub name: String,
242 #[serde(skip_serializing_if = "Option::is_none")]
243 pub memory_total_bytes: Option<u64>,
244 #[serde(skip_serializing_if = "Option::is_none")]
245 pub memory_used_bytes: Option<u64>,
246}
247
248#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
249pub struct DiskInfo {
250 pub name: String,
251 #[serde(skip_serializing_if = "Option::is_none")]
252 pub mount_point: Option<String>,
253 pub total_bytes: u64,
254 pub available_bytes: u64,
255 #[serde(skip_serializing_if = "Option::is_none")]
256 pub filesystem: Option<String>,
257}
258
259#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
260pub struct AgentSystemInfo {
261 pub cpu: CpuInfo,
262 pub memory: MemoryInfo,
263 #[serde(default, skip_serializing_if = "Vec::is_empty")]
264 pub gpus: Vec<GpuInfo>,
265 #[serde(default, skip_serializing_if = "Vec::is_empty")]
266 pub disks: Vec<DiskInfo>,
267}
268
269#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
270pub struct AgentSystemSnapshot {
271 pub captured_at: DateTime<Utc>,
272 pub system: AgentSystemInfo,
273}
274
275#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
276pub struct VncTarget {
277 pub id: String,
279 pub name: String,
281 pub url: String,
283 #[serde(skip_serializing_if = "Option::is_none")]
284 pub notes: Option<String>,
285}
286
287#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, ToSchema)]
288#[serde(rename_all = "snake_case")]
289pub enum VncSessionState {
290 Pending,
291 Active,
292 Revoked,
293 Expired,
294}
295
296#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
297pub struct VncSession {
298 pub id: Uuid,
299 pub target_id: String,
300 pub state: VncSessionState,
301 pub created_at: DateTime<Utc>,
302 pub expires_at: DateTime<Utc>,
303 #[serde(skip_serializing_if = "Option::is_none")]
306 pub connect_url: Option<String>,
307 #[serde(skip_serializing_if = "Option::is_none")]
309 pub password: Option<String>,
310 #[serde(skip_serializing_if = "Option::is_none")]
311 pub token: Option<String>,
312 #[serde(skip_serializing_if = "Option::is_none")]
313 pub created_by: Option<Uuid>,
314}
315
316#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
317pub struct CreateVncSessionRequest {
318 #[validate(length(min = 1, max = 128))]
319 pub target_id: String,
320 #[serde(default)]
322 pub duration_minutes: Option<u64>,
323 #[serde(skip_serializing_if = "Option::is_none", default)]
324 #[validate(length(max = 64))]
325 pub password: Option<String>,
326}
327
328#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
329pub struct Agent {
330 pub id: Uuid,
331 pub name: String,
332 pub status: AgentStatus,
333 pub last_seen: DateTime<Utc>,
334 #[serde(skip_serializing_if = "Option::is_none")]
335 pub load: Option<f64>,
336 #[serde(skip_serializing_if = "Option::is_none")]
337 pub queue_depth: Option<u32>,
338 pub capabilities: Capabilities,
339 #[serde(default)]
340 pub metadata: HashMap<String, Value>,
341 #[serde(skip_serializing_if = "Option::is_none")]
342 pub system: Option<AgentSystemInfo>,
343}
344
345#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
346pub struct RegisterAgentRequest {
347 #[validate(length(min = 1, max = 128))]
348 pub name: String,
349 pub capabilities: Capabilities,
350 #[serde(default)]
351 pub metadata: HashMap<String, Value>,
352}
353
354#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
355pub struct AgentWithToken {
356 #[serde(flatten)]
357 pub agent: Agent,
358 pub token: String,
359}
360
361#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
362pub struct UpdateAgentRequest {
363 #[validate(length(min = 1, max = 128))]
364 #[serde(skip_serializing_if = "Option::is_none")]
365 pub name: Option<String>,
366 #[serde(skip_serializing_if = "Option::is_none")]
367 pub status: Option<AgentStatus>,
368 #[serde(skip_serializing_if = "Option::is_none")]
369 pub metadata: Option<HashMap<String, Value>>,
370}
371
372#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
373pub struct Heartbeat {
374 #[serde(skip_serializing_if = "Option::is_none")]
375 pub status: Option<AgentStatus>,
376 #[serde(skip_serializing_if = "Option::is_none")]
377 pub load: Option<f64>,
378 #[serde(skip_serializing_if = "Option::is_none")]
379 pub queue_depth: Option<u32>,
380 #[serde(skip_serializing_if = "Option::is_none")]
381 pub system: Option<AgentSystemInfo>,
382}
383
384#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, ToSchema)]
385#[serde(rename_all = "snake_case")]
386pub enum AgentInstallChannel {
387 Ssh,
388 Wmi,
389}
390
391#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, ToSchema)]
392#[serde(rename_all = "snake_case")]
393pub enum DeploymentStatus {
394 Pending,
395 Running,
396 Succeeded,
397 Failed,
398}
399
400#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
401pub struct DeploymentLog {
402 pub ts: DateTime<Utc>,
403 pub level: String,
404 pub message: String,
405}
406
407#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, Validate)]
408pub struct DeploymentAgentConfig {
409 #[validate(length(min = 1, max = 128))]
410 #[serde(skip_serializing_if = "Option::is_none")]
411 pub name: Option<String>,
412 pub capabilities: Capabilities,
413 #[serde(default)]
414 pub metadata: HashMap<String, Value>,
415}
416
417#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, Default)]
418pub struct DeploymentInstallOptions {
419 #[serde(skip_serializing_if = "Option::is_none")]
420 pub download_url: Option<String>,
421 #[serde(skip_serializing_if = "Option::is_none")]
422 pub install_path: Option<String>,
423 #[serde(skip_serializing_if = "Option::is_none")]
424 pub bootstrap_script: Option<String>,
425}
426
427#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
428pub struct SshDeployment {
429 #[validate(length(min = 1, max = 255))]
430 pub host: String,
431 #[serde(default = "SshDeployment::default_port")]
432 pub port: u16,
433 #[validate(length(min = 1, max = 64))]
434 pub username: String,
435 #[serde(skip_serializing_if = "Option::is_none")]
436 pub private_key: Option<String>,
437 #[serde(skip_serializing_if = "Option::is_none")]
438 pub password: Option<String>,
439 #[serde(skip_serializing_if = "Option::is_none")]
440 pub install_path: Option<String>,
441}
442
443impl SshDeployment {
444 #[must_use]
445 const fn default_port() -> u16 {
446 22
447 }
448}
449
450#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
451pub struct WmiDeployment {
452 #[validate(length(min = 1, max = 255))]
453 pub host: String,
454 #[validate(length(min = 1, max = 128))]
455 pub username: String,
456 #[validate(length(min = 1, max = 256))]
457 pub password: String,
458 #[serde(skip_serializing_if = "Option::is_none")]
459 pub namespace: Option<String>,
460}
461
462#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
463pub struct CreateAgentDeploymentRequest {
464 pub channel: AgentInstallChannel,
465 #[validate(nested)]
466 #[serde(skip_serializing_if = "Option::is_none")]
467 pub ssh: Option<SshDeployment>,
468 #[validate(nested)]
469 #[serde(skip_serializing_if = "Option::is_none")]
470 pub wmi: Option<WmiDeployment>,
471 #[validate(nested)]
472 pub agent: DeploymentAgentConfig,
473 #[serde(skip_serializing_if = "Option::is_none")]
474 pub install: Option<DeploymentInstallOptions>,
475}
476
477#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
478pub struct AgentDeploymentTarget {
479 pub host: String,
480 #[serde(skip_serializing_if = "Option::is_none")]
481 pub port: Option<u16>,
482 #[serde(skip_serializing_if = "Option::is_none")]
483 pub username: Option<String>,
484 #[serde(skip_serializing_if = "Option::is_none")]
485 pub transport: Option<String>,
486}
487
488#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
489pub struct AgentDeployment {
490 pub id: Uuid,
491 pub channel: AgentInstallChannel,
492 pub target: AgentDeploymentTarget,
493 pub status: DeploymentStatus,
494 #[serde(skip_serializing_if = "Option::is_none")]
495 pub status_message: Option<String>,
496 pub created_at: DateTime<Utc>,
497 pub updated_at: DateTime<Utc>,
498 #[serde(skip_serializing_if = "Option::is_none")]
499 pub agent_id: Option<Uuid>,
500 #[serde(skip_serializing_if = "Option::is_none")]
501 pub agent_token: Option<String>,
502 #[serde(skip_serializing_if = "Option::is_none")]
503 pub install_path: Option<String>,
504 #[serde(default, skip_serializing_if = "Vec::is_empty")]
505 pub logs: Vec<DeploymentLog>,
506}
507
508#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, ToSchema)]
509#[serde(rename_all = "snake_case")]
510pub enum OAuthGrantType {
511 AuthorizationCode,
512 RefreshToken,
513 ClientCredentials,
514}
515
516impl OAuthGrantType {
517 #[must_use]
518 pub const fn as_str(&self) -> &'static str {
519 match self {
520 Self::AuthorizationCode => "authorization_code",
521 Self::RefreshToken => "refresh_token",
522 Self::ClientCredentials => "client_credentials",
523 }
524 }
525}
526
527impl FromStr for OAuthGrantType {
528 type Err = ();
529
530 fn from_str(value: &str) -> Result<Self, Self::Err> {
531 match value {
532 "authorization_code" | "code" => Ok(Self::AuthorizationCode),
533 "refresh_token" => Ok(Self::RefreshToken),
534 "client_credentials" => Ok(Self::ClientCredentials),
535 _ => Err(()),
536 }
537 }
538}
539
540#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
541#[serde(rename_all = "lowercase")]
542pub enum CodeChallengeMethod {
543 Plain,
544 S256,
545}
546
547impl CodeChallengeMethod {
548 #[must_use]
549 pub const fn as_str(&self) -> &'static str {
550 match self {
551 Self::Plain => "plain",
552 Self::S256 => "S256",
553 }
554 }
555}
556
557impl FromStr for CodeChallengeMethod {
558 type Err = ();
559
560 fn from_str(value: &str) -> Result<Self, Self::Err> {
561 match value {
562 "plain" => Ok(Self::Plain),
563 "S256" | "s256" => Ok(Self::S256),
564 _ => Err(()),
565 }
566 }
567}
568
569#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
570pub struct OAuthClient {
571 pub client_id: String,
572 #[serde(skip_serializing_if = "Option::is_none")]
573 pub name: Option<String>,
574 pub redirect_uris: Vec<String>,
575 pub allowed_scopes: Vec<String>,
576 pub allowed_grant_types: Vec<OAuthGrantType>,
577 pub is_confidential: bool,
578 pub is_active: bool,
579 #[serde(skip_serializing_if = "Option::is_none")]
580 pub secret_preview: Option<String>,
581 pub created_at: DateTime<Utc>,
582 pub updated_at: DateTime<Utc>,
583}
584
585#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
586pub struct OAuthClientWithSecret {
587 pub client: OAuthClient,
588 #[serde(skip_serializing_if = "Option::is_none")]
589 pub client_secret: Option<String>,
590}
591
592#[derive(Debug, Clone)]
593pub struct StoredOAuthClient {
594 pub client: OAuthClient,
595 pub secret_hash: Option<String>,
596}
597
598#[derive(Debug, Clone)]
599pub struct NewOAuthClient {
600 pub client_id: String,
601 pub name: Option<String>,
602 pub secret_hash: Option<String>,
603 pub secret_preview: Option<String>,
604 pub redirect_uris: Vec<String>,
605 pub allowed_scopes: Vec<String>,
606 pub allowed_grant_types: Vec<OAuthGrantType>,
607 pub is_confidential: bool,
608 pub is_active: bool,
609 pub created_at: DateTime<Utc>,
610 pub updated_at: DateTime<Utc>,
611}
612
613#[derive(Debug, Clone)]
614pub struct OAuthClientUpdate {
615 pub name: Option<String>,
616 pub redirect_uris: Option<Vec<String>>,
617 pub allowed_scopes: Option<Vec<String>>,
618 pub allowed_grant_types: Option<Vec<OAuthGrantType>>,
619 pub is_confidential: Option<bool>,
620 pub is_active: Option<bool>,
621 pub secret_hash: Option<String>,
622 pub secret_preview: Option<String>,
623 pub updated_at: DateTime<Utc>,
624}
625
626#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
627pub struct OAuthClientListResponse {
628 pub clients: Vec<OAuthClient>,
629}
630
631#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
632pub struct CreateOAuthClientRequest {
633 #[validate(length(min = 3, max = 96))]
634 pub name: Option<String>,
635 #[validate(length(min = 8, max = 96))]
636 pub client_id: Option<String>,
637 #[validate(length(min = 1))]
638 pub redirect_uris: Vec<String>,
639 #[validate(length(min = 1))]
640 pub allowed_scopes: Vec<String>,
641 #[validate(length(min = 1))]
642 pub allowed_grant_types: Vec<OAuthGrantType>,
643 pub is_confidential: Option<bool>,
644 #[validate(length(min = 16, max = 256))]
645 pub client_secret: Option<String>,
646 pub is_active: Option<bool>,
647}
648
649#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
650pub struct UpdateOAuthClientRequest {
651 #[validate(length(min = 3, max = 96))]
652 pub name: Option<String>,
653 #[validate(length(min = 1))]
654 pub redirect_uris: Option<Vec<String>>,
655 #[validate(length(min = 1))]
656 pub allowed_scopes: Option<Vec<String>>,
657 #[validate(length(min = 1))]
658 pub allowed_grant_types: Option<Vec<OAuthGrantType>>,
659 pub is_confidential: Option<bool>,
660 pub is_active: Option<bool>,
661}
662
663#[derive(Debug, Clone)]
664pub struct OAuthAuthorizationCode {
665 pub code: String,
666 pub client_id: String,
667 pub user_id: Uuid,
668 pub redirect_uri: String,
669 pub scope: Vec<String>,
670 pub code_challenge: Option<String>,
671 pub code_challenge_method: Option<CodeChallengeMethod>,
672 pub nonce: Option<String>,
673 pub created_at: DateTime<Utc>,
674 pub expires_at: DateTime<Utc>,
675}
676
677#[derive(Debug, Clone)]
678pub struct OAuthRefreshTokenData {
679 pub fingerprint: String,
680 pub token_hash: String,
681 pub client_id: String,
682 pub user_id: Option<Uuid>,
683 pub scope: Vec<String>,
684 pub created_at: DateTime<Utc>,
685 pub expires_at: DateTime<Utc>,
686}
687
688#[derive(Debug, Deserialize, Serialize, IntoParams, ToSchema)]
689#[serde(rename_all = "snake_case")]
690pub struct AuthorizationRequest {
691 pub response_type: Option<String>,
692 pub client_id: String,
693 pub redirect_uri: Option<String>,
694 pub scope: Option<String>,
695 pub state: Option<String>,
696 pub code_challenge: Option<String>,
697 pub code_challenge_method: Option<String>,
698 pub nonce: Option<String>,
699}
700
701#[derive(Debug, Deserialize, Serialize, ToSchema)]
702#[serde(rename_all = "snake_case")]
703pub struct TokenRequest {
704 pub grant_type: String,
705 pub code: Option<String>,
706 pub redirect_uri: Option<String>,
707 pub code_verifier: Option<String>,
708 pub refresh_token: Option<String>,
709 pub scope: Option<String>,
710 pub client_id: Option<String>,
711 pub client_secret: Option<String>,
712}
713
714#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, ToSchema)]
715#[serde(rename_all = "snake_case")]
716pub enum TaskKind {
717 Command,
718 Keyboard,
719 Mouse,
720 Capture,
721 SystemInfo,
722 FilesystemCrawl,
723 Custom,
724}
725
726#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, ToSchema)]
727#[serde(rename_all = "snake_case")]
728pub enum TaskState {
729 Queued,
730 Assigned,
731 Running,
732 WaitingInput,
733 Cancelling,
734 Cancelled,
735 Succeeded,
736 Failed,
737}
738
739#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
740pub struct TaskStatus {
741 pub state: TaskState,
742 #[serde(default, skip_serializing_if = "Option::is_none")]
743 pub progress: Option<f64>,
744 #[serde(skip_serializing_if = "Option::is_none")]
745 pub step: Option<String>,
746 #[serde(skip_serializing_if = "Option::is_none")]
747 pub message: Option<String>,
748 #[serde(skip_serializing_if = "Option::is_none")]
749 pub updated_at: Option<DateTime<Utc>>,
750 #[serde(skip_serializing_if = "Option::is_none")]
751 pub error: Option<String>,
752}
753
754impl TaskStatus {
755 #[must_use]
756 pub fn queued(now: DateTime<Utc>) -> Self {
757 Self {
758 state: TaskState::Queued,
759 progress: Some(0.0),
760 step: None,
761 message: None,
762 updated_at: Some(now),
763 error: None,
764 }
765 }
766
767 #[must_use]
768 pub fn with_state(mut self, state: TaskState, now: DateTime<Utc>) -> Self {
769 self.state = state;
770 self.updated_at = Some(now);
771 self
772 }
773}
774
775#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
776pub struct CreateTaskRequest {
777 pub kind: TaskKind,
778 #[serde(skip_serializing_if = "Option::is_none")]
779 pub agent_id: Option<Uuid>,
780 #[serde(skip_serializing_if = "Option::is_none")]
781 pub run_id: Option<Uuid>,
782 #[serde(default)]
783 pub payload: Value,
784 #[serde(default)]
785 pub priority: i32,
786 #[serde(skip_serializing_if = "Option::is_none")]
787 pub deadline: Option<DateTime<Utc>>,
788}
789
790#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
791pub struct AgentTask {
792 pub id: Uuid,
793 #[serde(skip_serializing_if = "Option::is_none")]
794 pub agent_id: Option<Uuid>,
795 #[serde(skip_serializing_if = "Option::is_none")]
796 pub run_id: Option<Uuid>,
797 #[serde(skip_serializing_if = "Option::is_none")]
798 pub agent_info: Option<AgentSystemInfo>,
799 pub kind: TaskKind,
800 pub payload: Value,
801 pub priority: i32,
802 pub status: TaskStatus,
803 pub created_at: DateTime<Utc>,
804 pub updated_at: DateTime<Utc>,
805 #[serde(skip_serializing_if = "Option::is_none")]
806 pub deadline: Option<DateTime<Utc>>,
807 #[serde(skip_serializing_if = "Option::is_none")]
808 pub result: Option<TaskResult>,
809 #[serde(default, skip_serializing_if = "Vec::is_empty")]
810 pub artifacts: Vec<Artifact>,
811}
812
813#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
814pub struct TaskStatusUpdate {
815 #[serde(skip_serializing_if = "Option::is_none")]
816 pub state: Option<TaskState>,
817 #[serde(skip_serializing_if = "Option::is_none")]
818 pub progress: Option<f64>,
819 #[serde(skip_serializing_if = "Option::is_none")]
820 pub step: Option<String>,
821 #[serde(skip_serializing_if = "Option::is_none")]
822 pub message: Option<String>,
823 #[serde(skip_serializing_if = "Option::is_none")]
824 pub error: Option<String>,
825}
826
827#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
828pub struct CancelRequest {
829 #[serde(skip_serializing_if = "Option::is_none")]
830 pub reason: Option<String>,
831}
832
833#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
834pub struct PollRequest {
835 #[serde(default = "PollRequest::default_max_tasks")]
836 pub max_tasks: u32,
837 #[serde(default = "PollRequest::default_wait_seconds")]
838 pub wait_seconds: u64,
839}
840
841impl PollRequest {
842 const fn default_max_tasks() -> u32 {
843 1
844 }
845
846 const fn default_wait_seconds() -> u64 {
847 15
848 }
849}
850
851#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, Default)]
852pub struct SystemInfoRequest {
853 #[serde(default)]
854 pub include_usage: bool,
855}
856
857#[allow(clippy::struct_excessive_bools)]
858#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, Default)]
859pub struct HashingRequest {
860 #[serde(default)]
861 pub md5: bool,
862 #[serde(default)]
863 pub sha256: bool,
864 #[serde(default)]
865 pub sha512: bool,
866 #[serde(default)]
867 pub blake3: bool,
868 #[serde(skip_serializing_if = "Option::is_none")]
869 pub max_concurrent: Option<u32>,
870 #[serde(skip_serializing_if = "Option::is_none")]
871 pub buffer_size: Option<u32>,
872}
873
874#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, Default)]
875pub struct FileHashes {
876 #[serde(skip_serializing_if = "Option::is_none")]
877 pub md5: Option<String>,
878 #[serde(skip_serializing_if = "Option::is_none")]
879 pub sha256: Option<String>,
880 #[serde(skip_serializing_if = "Option::is_none")]
881 pub sha512: Option<String>,
882 #[serde(skip_serializing_if = "Option::is_none")]
883 pub blake3: Option<String>,
884}
885
886#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, ToSchema, Default)]
887#[serde(rename_all = "snake_case")]
888pub enum FileVisibility {
889 #[default]
890 Private,
891 Shared,
892 Public,
893}
894
895#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
896pub struct CreateFileRequest {
897 #[validate(length(min = 1, max = 255))]
898 pub name: String,
899 #[validate(length(max = 1024))]
900 pub description: Option<String>,
901 #[validate(length(max = 256))]
902 pub content_type: Option<String>,
903 #[serde(default)]
904 pub visibility: FileVisibility,
905 #[serde(default)]
906 pub shared_with: Vec<Uuid>,
907 #[serde(skip_serializing_if = "Option::is_none")]
908 pub size_bytes: Option<i64>,
909 #[serde(skip_serializing_if = "Option::is_none")]
910 pub data_base64: Option<String>,
911 #[serde(skip_serializing_if = "Option::is_none")]
912 pub hashes: Option<FileHashes>,
913}
914
915#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
916pub struct CaptureFileRequest {
917 #[validate(length(min = 1, max = 255))]
918 pub name: String,
919 #[validate(length(max = 1024))]
920 pub description: Option<String>,
921 #[validate(length(max = 256))]
922 pub content_type: Option<String>,
923 #[serde(default)]
924 pub visibility: FileVisibility,
925 #[serde(default)]
926 pub shared_with: Vec<Uuid>,
927 #[serde(skip_serializing_if = "Option::is_none")]
928 pub size_bytes: Option<i64>,
929 #[serde(skip_serializing_if = "Option::is_none")]
930 pub data_base64: Option<String>,
931 #[serde(skip_serializing_if = "Option::is_none")]
932 pub hashes: Option<FileHashes>,
933}
934
935#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema, Default)]
936pub struct UpdateFileRequest {
937 #[serde(skip_serializing_if = "Option::is_none")]
938 #[validate(length(min = 1, max = 255))]
939 pub name: Option<String>,
940 #[serde(skip_serializing_if = "Option::is_none")]
941 #[validate(length(max = 1024))]
942 pub description: Option<String>,
943 #[serde(skip_serializing_if = "Option::is_none")]
944 pub visibility: Option<FileVisibility>,
945 #[serde(skip_serializing_if = "Option::is_none")]
946 pub shared_with: Option<Vec<Uuid>>,
947}
948
949#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
950pub struct FileMetadata {
951 pub id: Uuid,
952 pub owner_id: Uuid,
953 pub name: String,
954 #[serde(skip_serializing_if = "Option::is_none")]
955 pub description: Option<String>,
956 #[serde(skip_serializing_if = "Option::is_none")]
957 pub content_type: Option<String>,
958 pub size_bytes: i64,
959 pub visibility: FileVisibility,
960 #[serde(skip_serializing_if = "Option::is_none")]
961 pub hashes: Option<FileHashes>,
962 #[serde(default, skip_serializing_if = "Vec::is_empty")]
963 pub shared_with: Vec<Uuid>,
964 #[serde(skip_serializing_if = "Option::is_none")]
965 pub download_url: Option<String>,
966 pub created_at: DateTime<Utc>,
967 pub updated_at: DateTime<Utc>,
968}
969
970#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
971pub struct FileDownloadUrl {
972 pub url: String,
973 pub expires_in_seconds: u64,
974}
975
976#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, ToSchema)]
977#[serde(rename_all = "snake_case")]
978pub enum FilePermission {
979 Read,
980 Write,
981 Delete,
982 Admin,
983}
984
985impl std::str::FromStr for FilePermission {
986 type Err = ValidationError;
987
988 fn from_str(value: &str) -> Result<Self, Self::Err> {
989 match value.to_ascii_lowercase().as_str() {
990 "read" => Ok(Self::Read),
991 "write" => Ok(Self::Write),
992 "delete" => Ok(Self::Delete),
993 "admin" => Ok(Self::Admin),
994 _ => Err(ValidationError::new("file_permission")),
995 }
996 }
997}
998
999impl std::fmt::Display for FilePermission {
1000 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1001 let value = match self {
1002 Self::Read => "read",
1003 Self::Write => "write",
1004 Self::Delete => "delete",
1005 Self::Admin => "admin",
1006 };
1007 write!(f, "{value}")
1008 }
1009}
1010
1011#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
1012#[validate(schema(function = "validate_grant_file_permission"))]
1013pub struct GrantFilePermissionRequest {
1014 #[serde(skip_serializing_if = "Option::is_none")]
1015 pub user_id: Option<Uuid>,
1016 #[serde(skip_serializing_if = "Option::is_none")]
1017 pub team_id: Option<Uuid>,
1018 #[serde(skip_serializing_if = "Option::is_none")]
1019 #[validate(length(min = 1, max = 128))]
1020 pub role: Option<String>,
1021 pub permission: FilePermission,
1022 #[serde(skip_serializing_if = "Option::is_none")]
1023 pub expires_at: Option<DateTime<Utc>>,
1024}
1025
1026#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1027pub struct FilePermissionResponse {
1028 pub id: Uuid,
1029 pub file_id: Uuid,
1030 #[serde(skip_serializing_if = "Option::is_none")]
1031 pub user_id: Option<Uuid>,
1032 #[serde(skip_serializing_if = "Option::is_none")]
1033 pub team_id: Option<Uuid>,
1034 #[serde(skip_serializing_if = "Option::is_none")]
1035 pub role: Option<String>,
1036 pub permission: FilePermission,
1037 pub granted_by: Uuid,
1038 pub granted_at: DateTime<Utc>,
1039 #[serde(skip_serializing_if = "Option::is_none")]
1040 pub expires_at: Option<DateTime<Utc>>,
1041}
1042
1043#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1044pub struct FileDownloadResponse {
1045 pub downloaded_by: Uuid,
1046 pub downloaded_at: DateTime<Utc>,
1047 pub download_size: i64,
1048 #[serde(skip_serializing_if = "Option::is_none")]
1049 pub user_agent: Option<String>,
1050}
1051
1052#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1053pub struct FileStatsResponse {
1054 pub total_downloads: i64,
1055 pub total_download_size: i64,
1056 pub unique_downloaders: i64,
1057 pub recent_downloads: Vec<FileDownloadResponse>,
1058}
1059
1060#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
1061pub struct UploadFileRequest {
1062 #[validate(length(min = 1, max = 255))]
1063 pub filename: String,
1064 #[validate(length(min = 1, max = 256))]
1065 pub content_type: String,
1066 #[validate(range(min = 1))]
1067 pub file_size: i64,
1068 #[serde(skip_serializing_if = "Option::is_none")]
1069 #[validate(length(max = 1024))]
1070 pub description: Option<String>,
1071 #[serde(skip_serializing_if = "Option::is_none")]
1072 pub visibility: Option<FileVisibility>,
1073}
1074
1075#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1076pub struct PresignedUrlResponse {
1077 pub upload_url: String,
1078 pub expires_at: DateTime<Utc>,
1079 pub file_id: Uuid,
1080}
1081
1082#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
1083pub struct StartMultipartUploadRequest {
1084 #[validate(length(min = 1, max = 255))]
1085 pub filename: String,
1086 #[validate(length(min = 1, max = 256))]
1087 pub content_type: String,
1088 #[serde(skip_serializing_if = "Option::is_none")]
1089 pub expected_size: Option<i64>,
1090 #[serde(skip_serializing_if = "Option::is_none")]
1091 #[validate(length(max = 1024))]
1092 pub description: Option<String>,
1093 #[serde(skip_serializing_if = "Option::is_none")]
1094 pub visibility: Option<FileVisibility>,
1095}
1096
1097#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1098pub struct UploadSessionResponse {
1099 pub session_id: Uuid,
1100 pub upload_id: String,
1101 pub upload_url: String,
1102 pub expires_at: DateTime<Utc>,
1103}
1104
1105#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1106pub struct UploadPartInfo {
1107 pub part_number: i32,
1108 pub etag: String,
1109}
1110
1111#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
1112pub struct CompleteMultipartUploadRequest {
1113 #[validate(length(min = 1, max = 512))]
1114 pub upload_id: String,
1115 pub parts: Vec<UploadPartInfo>,
1116}
1117
1118#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, ToSchema)]
1119#[serde(rename_all = "snake_case")]
1120pub enum FilesystemEntryType {
1121 File,
1122 Directory,
1123 Symlink,
1124 Other,
1125}
1126
1127#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1128pub struct FilesystemEntry {
1129 pub path: String,
1130 pub entry_type: FilesystemEntryType,
1131 #[serde(skip_serializing_if = "Option::is_none")]
1132 pub size_bytes: Option<u64>,
1133 #[serde(skip_serializing_if = "Option::is_none")]
1134 pub modified: Option<DateTime<Utc>>,
1135 #[serde(skip_serializing_if = "Option::is_none")]
1136 pub hashes: Option<FileHashes>,
1137}
1138
1139#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1140pub struct FilesystemCrawlRequest {
1141 pub root: String,
1142 #[serde(skip_serializing_if = "Option::is_none")]
1143 pub max_depth: Option<u32>,
1144 #[serde(default)]
1145 pub follow_symlinks: bool,
1146 #[serde(skip_serializing_if = "Option::is_none")]
1147 pub hash: Option<HashingRequest>,
1148}
1149
1150#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1151pub struct FilesystemCrawlResult {
1152 pub root: String,
1153 pub entries: Vec<FilesystemEntry>,
1154}
1155
1156#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1157pub struct TaskResult {
1158 pub status: String,
1159 #[serde(default)]
1160 pub output: Value,
1161 #[serde(skip_serializing_if = "Option::is_none")]
1162 pub error: Option<String>,
1163 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1164 pub artifacts: Vec<Artifact>,
1165}
1166
1167#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1168pub struct TaskLogAppend {
1169 pub stream: Option<String>,
1170 pub lines: Vec<String>,
1171 #[serde(skip_serializing_if = "Option::is_none")]
1172 pub timestamp: Option<DateTime<Utc>>,
1173}
1174
1175#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1176pub struct TaskLogEvent {
1177 pub ts: DateTime<Utc>,
1178 pub stream: String,
1179 pub line: String,
1180}
1181
1182#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1183pub struct RunLogEvent {
1184 pub ts: DateTime<Utc>,
1185 pub stream: String,
1186 pub line: String,
1187 #[serde(skip_serializing_if = "Option::is_none")]
1188 pub task_id: Option<Uuid>,
1189}
1190
1191#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1192pub struct CommandRequest {
1193 pub command: String,
1194 #[serde(default)]
1195 pub args: Vec<String>,
1196 #[serde(skip_serializing_if = "Option::is_none")]
1197 pub cwd: Option<String>,
1198 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
1199 pub env: HashMap<String, String>,
1200 #[serde(skip_serializing_if = "Option::is_none")]
1201 pub timeout_seconds: Option<u64>,
1202}
1203
1204#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1205pub struct CommandResponse {
1206 pub command_id: Uuid,
1207 pub task_id: Uuid,
1208}
1209
1210#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1211pub struct CommandOutputEvent {
1212 pub ts: DateTime<Utc>,
1213 pub stream: String,
1214 #[serde(skip_serializing_if = "Option::is_none")]
1215 pub data: Option<String>,
1216 #[serde(skip_serializing_if = "Option::is_none")]
1217 pub exit_code: Option<i32>,
1218}
1219
1220#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1221pub struct KeyboardInput {
1222 pub text: String,
1223 #[serde(skip_serializing_if = "Option::is_none")]
1224 pub delay_ms: Option<u64>,
1225}
1226
1227#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1228pub struct MouseInput {
1229 pub action: String,
1230 #[serde(skip_serializing_if = "Option::is_none")]
1231 pub x: Option<i32>,
1232 #[serde(skip_serializing_if = "Option::is_none")]
1233 pub y: Option<i32>,
1234 #[serde(skip_serializing_if = "Option::is_none")]
1235 pub button: Option<String>,
1236 #[serde(skip_serializing_if = "Option::is_none")]
1237 pub scroll_x: Option<i32>,
1238 #[serde(skip_serializing_if = "Option::is_none")]
1239 pub scroll_y: Option<i32>,
1240}
1241
1242#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1243pub struct ScreenCaptureRequest {
1244 #[serde(skip_serializing_if = "Option::is_none")]
1245 pub region: Option<CaptureRegion>,
1246 #[serde(default)]
1247 pub include_cursor: bool,
1248 #[serde(skip_serializing_if = "Option::is_none")]
1249 pub format: Option<String>,
1250 #[serde(skip_serializing_if = "Option::is_none")]
1251 pub quality: Option<u8>,
1252 #[serde(skip_serializing_if = "Option::is_none")]
1253 pub display: Option<u32>,
1254}
1255
1256#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1257pub struct CaptureRegion {
1258 pub x: i32,
1259 pub y: i32,
1260 pub width: i32,
1261 pub height: i32,
1262}
1263
1264#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1265pub struct ScreenCaptureTicket {
1266 pub capture_id: Uuid,
1267 pub task_id: Uuid,
1268}
1269
1270#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1271pub struct ScreenCapture {
1272 pub id: Uuid,
1273 pub task_id: Uuid,
1274 pub agent_id: Uuid,
1275 pub status: String,
1276 pub format: String,
1277 #[serde(skip_serializing_if = "Option::is_none")]
1278 pub size_bytes: Option<u64>,
1279 #[serde(skip_serializing_if = "Option::is_none")]
1280 pub download_url: Option<String>,
1281 pub created_at: DateTime<Utc>,
1282}
1283
1284#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1285pub struct Artifact {
1286 pub id: Uuid,
1287 pub task_id: Uuid,
1288 pub name: String,
1289 pub content_type: String,
1290 pub size_bytes: u64,
1291 pub download_url: String,
1292}
1293
1294#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
1295pub struct CreateArtifactRequest {
1296 pub task_id: Uuid,
1297 #[validate(length(min = 1))]
1298 pub name: String,
1299 #[validate(length(min = 1))]
1300 pub content_type: String,
1301 pub size_bytes: u64,
1302}
1303
1304#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1305pub struct ArtifactUpload {
1306 pub artifact: Artifact,
1307 pub upload_url: String,
1308 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
1309 pub headers: HashMap<String, String>,
1310}
1311
1312#[derive(Debug, Clone)]
1313pub struct StoredUser {
1314 pub user: User,
1315 pub password_hash: Option<String>,
1316}
1317
1318#[derive(Debug, Clone)]
1319pub struct RefreshTokenData {
1320 pub user_id: Uuid,
1321 pub expires_at: DateTime<Utc>,
1322 pub token_hash: String,
1323 pub fingerprint: String,
1324}
1325
1326#[derive(Debug, Clone)]
1327pub struct OAuthStateRecord {
1328 pub provider: String,
1329}
1330
1331#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1332pub struct ErrorResponse {
1333 pub error: String,
1334 pub status: u16,
1335}
1336
1337#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, ToSchema)]
1338#[serde(rename_all = "snake_case")]
1339pub enum ApiKeyRole {
1340 Owner,
1341 Manager,
1342 Contributor,
1343 Viewer,
1344}
1345
1346impl ApiKeyRole {
1347 #[must_use]
1348 pub const fn as_str(&self) -> &'static str {
1349 match self {
1350 Self::Owner => "owner",
1351 Self::Manager => "manager",
1352 Self::Contributor => "contributor",
1353 Self::Viewer => "viewer",
1354 }
1355 }
1356}
1357
1358#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, ToSchema)]
1359#[serde(rename_all = "snake_case")]
1360pub enum ApiKeyStatus {
1361 Active,
1362 Revoked,
1363 Expired,
1364}
1365
1366impl ApiKeyStatus {
1367 #[must_use]
1368 pub const fn as_str(&self) -> &'static str {
1369 match self {
1370 Self::Active => "active",
1371 Self::Revoked => "revoked",
1372 Self::Expired => "expired",
1373 }
1374 }
1375}
1376
1377impl FromStr for ApiKeyRole {
1378 type Err = ();
1379
1380 fn from_str(value: &str) -> Result<Self, Self::Err> {
1381 match value {
1382 "owner" => Ok(Self::Owner),
1383 "manager" => Ok(Self::Manager),
1384 "contributor" => Ok(Self::Contributor),
1385 "viewer" => Ok(Self::Viewer),
1386 _ => Err(()),
1387 }
1388 }
1389}
1390
1391impl FromStr for ApiKeyStatus {
1392 type Err = ();
1393
1394 fn from_str(value: &str) -> Result<Self, Self::Err> {
1395 match value {
1396 "active" => Ok(Self::Active),
1397 "revoked" => Ok(Self::Revoked),
1398 "expired" => Ok(Self::Expired),
1399 _ => Err(()),
1400 }
1401 }
1402}
1403
1404#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, ToSchema)]
1405#[serde(transparent)]
1406pub struct ApiKeyScope(pub String);
1407
1408impl ApiKeyScope {
1409 #[must_use]
1410 pub fn new(value: impl Into<String>) -> Self {
1411 Self(value.into())
1412 }
1413
1414 #[must_use]
1415 pub fn as_str(&self) -> &str {
1416 &self.0
1417 }
1418}
1419
1420#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1421pub struct ApiKey {
1422 pub id: Uuid,
1423 pub name: String,
1424 #[serde(skip_serializing_if = "Option::is_none")]
1425 pub description: Option<String>,
1426 pub role: ApiKeyRole,
1427 #[serde(skip_serializing_if = "Option::is_none")]
1428 pub scopes: Option<Vec<ApiKeyScope>>,
1429 pub status: ApiKeyStatus,
1430 #[serde(skip_serializing_if = "Option::is_none")]
1431 pub metadata: Option<HashMap<String, String>>,
1432 #[serde(skip_serializing_if = "Option::is_none")]
1433 pub expires_at: Option<DateTime<Utc>>,
1434 #[serde(skip_serializing_if = "Option::is_none")]
1435 pub last_used_at: Option<DateTime<Utc>>,
1436 pub created_at: DateTime<Utc>,
1437 pub updated_at: DateTime<Utc>,
1438 pub created_by: Uuid,
1439 #[serde(skip_serializing_if = "Option::is_none")]
1440 pub managed_by: Option<Uuid>,
1441 #[serde(skip_serializing_if = "Option::is_none")]
1442 pub token_preview: Option<String>,
1443}
1444
1445impl ApiKey {
1446 #[must_use]
1447 pub fn to_summary(&self) -> ApiKeySummary {
1448 ApiKeySummary {
1449 id: self.id,
1450 name: self.name.clone(),
1451 role: self.role.clone(),
1452 status: self.status.clone(),
1453 created_at: self.created_at,
1454 expires_at: self.expires_at,
1455 last_used_at: self.last_used_at,
1456 token_preview: self.token_preview.clone(),
1457 }
1458 }
1459}
1460
1461#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1462pub struct ApiKeySummary {
1463 pub id: Uuid,
1464 pub name: String,
1465 pub role: ApiKeyRole,
1466 pub status: ApiKeyStatus,
1467 pub created_at: DateTime<Utc>,
1468 #[serde(skip_serializing_if = "Option::is_none")]
1469 pub expires_at: Option<DateTime<Utc>>,
1470 #[serde(skip_serializing_if = "Option::is_none")]
1471 pub last_used_at: Option<DateTime<Utc>>,
1472 #[serde(skip_serializing_if = "Option::is_none")]
1473 pub token_preview: Option<String>,
1474}
1475
1476#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1477pub struct ApiKeyWithSecret {
1478 #[serde(flatten)]
1479 pub api_key: ApiKey,
1480 pub secret: String,
1481}
1482
1483#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1484pub struct CreateApiKeyRequest {
1485 pub name: String,
1486 pub description: Option<String>,
1487 pub role: ApiKeyRole,
1488 pub scopes: Option<Vec<ApiKeyScope>>,
1489 pub expires_at: Option<DateTime<Utc>>,
1490 pub ttl_days: Option<i32>,
1491 pub metadata: Option<HashMap<String, String>>,
1492}
1493
1494#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1495pub struct UpdateApiKeyRequest {
1496 pub name: Option<String>,
1497 pub description: Option<Option<String>>,
1498 pub role: Option<ApiKeyRole>,
1499 pub scopes: Option<Option<Vec<ApiKeyScope>>>,
1500 pub status: Option<ApiKeyStatus>,
1501 pub expires_at: Option<Option<DateTime<Utc>>>,
1502 pub ttl_days: Option<i32>,
1503 pub metadata: Option<Option<HashMap<String, String>>>,
1504}
1505
1506#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1507pub struct RotateApiKeyRequest {
1508 pub expires_at: Option<DateTime<Utc>>,
1509 pub ttl_days: Option<i32>,
1510 pub reason: Option<String>,
1511}
1512
1513#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1514pub struct ApiKeyListResponse {
1515 pub object: String,
1516 pub data: Vec<ApiKeySummary>,
1517 pub has_more: bool,
1518 #[serde(skip_serializing_if = "Option::is_none")]
1519 pub first_id: Option<Uuid>,
1520 #[serde(skip_serializing_if = "Option::is_none")]
1521 pub last_id: Option<Uuid>,
1522}
1523
1524#[derive(Debug, Clone)]
1525pub struct NewApiKey {
1526 pub id: Uuid,
1527 pub name: String,
1528 pub description: Option<String>,
1529 pub role: ApiKeyRole,
1530 pub scopes: Option<Vec<ApiKeyScope>>,
1531 pub status: ApiKeyStatus,
1532 pub secret_hash: String,
1533 pub token_preview: Option<String>,
1534 pub created_by: Uuid,
1535 pub managed_by: Option<Uuid>,
1536 pub metadata: Option<HashMap<String, String>>,
1537 pub created_at: DateTime<Utc>,
1538 pub updated_at: DateTime<Utc>,
1539 pub expires_at: Option<DateTime<Utc>>,
1540 pub last_used_at: Option<DateTime<Utc>>,
1541}
1542
1543#[derive(Debug, Clone)]
1544pub struct ApiKeyUpdate {
1545 pub name: Option<String>,
1546 pub description: Option<Option<String>>,
1547 pub role: Option<ApiKeyRole>,
1548 pub scopes: Option<Option<Vec<ApiKeyScope>>>,
1549 pub status: Option<ApiKeyStatus>,
1550 pub token_preview: Option<Option<String>>,
1551 pub secret_hash: Option<String>,
1552 pub expires_at: Option<Option<DateTime<Utc>>>,
1553 pub metadata: Option<Option<HashMap<String, String>>>,
1554 pub managed_by: Option<Uuid>,
1555 pub last_used_at: Option<Option<DateTime<Utc>>>,
1556 pub updated_at: DateTime<Utc>,
1557}
1558
1559impl ApiKeyUpdate {
1560 #[must_use]
1561 pub const fn new(updated_at: DateTime<Utc>) -> Self {
1562 Self {
1563 name: None,
1564 description: None,
1565 role: None,
1566 scopes: None,
1567 status: None,
1568 token_preview: None,
1569 secret_hash: None,
1570 expires_at: None,
1571 metadata: None,
1572 managed_by: None,
1573 last_used_at: None,
1574 updated_at,
1575 }
1576 }
1577}
1578
1579#[derive(Debug, Clone)]
1580pub struct StoredApiKey {
1581 pub api_key: ApiKey,
1582 pub secret_hash: String,
1583}
1584
1585impl StoredApiKey {
1586 #[must_use]
1587 pub fn into_api_key(self) -> ApiKey {
1588 self.api_key
1589 }
1590}
1591
1592#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, ToSchema)]
1593#[serde(rename_all = "snake_case")]
1594pub enum OrganizationRole {
1595 Owner,
1596 Admin,
1597 Member,
1598 Viewer,
1599}
1600
1601impl OrganizationRole {
1602 #[must_use]
1603 pub const fn is_admin_like(&self) -> bool {
1604 matches!(self, Self::Owner | Self::Admin)
1605 }
1606
1607 #[must_use]
1608 pub const fn as_str(&self) -> &'static str {
1609 match self {
1610 Self::Owner => "owner",
1611 Self::Admin => "admin",
1612 Self::Member => "member",
1613 Self::Viewer => "viewer",
1614 }
1615 }
1616}
1617
1618impl FromStr for OrganizationRole {
1619 type Err = ();
1620
1621 fn from_str(value: &str) -> Result<Self, Self::Err> {
1622 match value {
1623 "owner" => Ok(Self::Owner),
1624 "admin" => Ok(Self::Admin),
1625 "member" => Ok(Self::Member),
1626 "viewer" => Ok(Self::Viewer),
1627 _ => Err(()),
1628 }
1629 }
1630}
1631
1632#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, ToSchema)]
1633#[serde(rename_all = "snake_case")]
1634pub enum OrganizationMemberStatus {
1635 Pending,
1636 Active,
1637 Suspended,
1638 Removed,
1639}
1640
1641impl OrganizationMemberStatus {
1642 #[must_use]
1643 pub const fn as_str(&self) -> &'static str {
1644 match self {
1645 Self::Pending => "pending",
1646 Self::Active => "active",
1647 Self::Suspended => "suspended",
1648 Self::Removed => "removed",
1649 }
1650 }
1651}
1652
1653impl FromStr for OrganizationMemberStatus {
1654 type Err = ();
1655
1656 fn from_str(value: &str) -> Result<Self, Self::Err> {
1657 match value {
1658 "pending" => Ok(Self::Pending),
1659 "active" => Ok(Self::Active),
1660 "suspended" => Ok(Self::Suspended),
1661 "removed" => Ok(Self::Removed),
1662 _ => Err(()),
1663 }
1664 }
1665}
1666
1667#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1668pub struct Organization {
1669 pub id: Uuid,
1670 pub name: String,
1671 pub slug: String,
1672 #[serde(skip_serializing_if = "Option::is_none")]
1673 pub description: Option<String>,
1674 #[serde(skip_serializing_if = "Option::is_none")]
1675 pub metadata: Option<HashMap<String, String>>,
1676 pub created_by: Uuid,
1677 pub created_at: DateTime<Utc>,
1678 pub updated_at: DateTime<Utc>,
1679 pub is_active: bool,
1680 pub member_count: usize,
1681}
1682
1683#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
1684pub struct CreateOrganizationRequest {
1685 #[validate(length(min = 3, max = 128))]
1686 pub name: String,
1687 #[validate(length(min = 3, max = 64))]
1688 pub slug: Option<String>,
1689 #[validate(length(max = 1024))]
1690 pub description: Option<String>,
1691 pub metadata: Option<HashMap<String, String>>,
1692}
1693
1694#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
1695pub struct UpdateOrganizationRequest {
1696 #[validate(length(min = 3, max = 128))]
1697 pub name: Option<String>,
1698 #[validate(length(min = 3, max = 64))]
1699 pub slug: Option<Option<String>>,
1700 #[validate(length(max = 1024))]
1701 pub description: Option<Option<String>>,
1702 pub metadata: Option<Option<HashMap<String, String>>>,
1703 pub is_active: Option<bool>,
1704}
1705
1706#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1707pub struct OrganizationSummary {
1708 #[serde(flatten)]
1709 pub organization: Organization,
1710}
1711
1712#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1713pub struct OrganizationListResponse {
1714 pub organizations: Vec<OrganizationSummary>,
1715}
1716
1717#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1718pub struct OrganizationMember {
1719 pub user_id: Uuid,
1720 pub role: OrganizationRole,
1721 pub status: OrganizationMemberStatus,
1722 #[serde(skip_serializing_if = "Option::is_none")]
1723 pub invited_by: Option<Uuid>,
1724 #[serde(skip_serializing_if = "Option::is_none")]
1725 pub invited_at: Option<DateTime<Utc>>,
1726 #[serde(skip_serializing_if = "Option::is_none")]
1727 pub joined_at: Option<DateTime<Utc>>,
1728}
1729
1730#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1731pub struct OrganizationMemberListResponse {
1732 pub members: Vec<OrganizationMember>,
1733}
1734
1735#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
1736pub struct AddOrganizationMemberRequest {
1737 pub user_id: Uuid,
1738 pub role: OrganizationRole,
1739}
1740
1741#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
1742pub struct UpdateOrganizationMemberRequest {
1743 pub role: Option<OrganizationRole>,
1744 pub status: Option<OrganizationMemberStatus>,
1745}
1746
1747#[derive(Debug, Clone)]
1748pub struct NewOrganization {
1749 pub id: Uuid,
1750 pub name: String,
1751 pub slug: String,
1752 pub description: Option<String>,
1753 pub metadata: Option<HashMap<String, String>>,
1754 pub created_by: Uuid,
1755 pub created_at: DateTime<Utc>,
1756 pub updated_at: DateTime<Utc>,
1757 pub is_active: bool,
1758}
1759
1760#[derive(Debug, Clone)]
1761pub struct OrganizationUpdate {
1762 pub name: Option<String>,
1763 pub slug: Option<Option<String>>,
1764 pub description: Option<Option<String>>,
1765 pub metadata: Option<Option<HashMap<String, String>>>,
1766 pub is_active: Option<bool>,
1767 pub updated_at: DateTime<Utc>,
1768}
1769
1770#[derive(Debug, Clone)]
1771pub struct NewOrganizationMember {
1772 pub organization_id: Uuid,
1773 pub user_id: Uuid,
1774 pub role: OrganizationRole,
1775 pub status: OrganizationMemberStatus,
1776 pub invited_by: Option<Uuid>,
1777 pub invited_at: Option<DateTime<Utc>>,
1778 pub joined_at: Option<DateTime<Utc>>,
1779}
1780
1781#[derive(Debug, Clone)]
1782pub struct OrganizationMemberUpdate {
1783 pub role: Option<OrganizationRole>,
1784 pub status: Option<OrganizationMemberStatus>,
1785 pub joined_at: Option<Option<DateTime<Utc>>>,
1786}
1787
1788#[derive(Debug, Clone, Default)]
1789pub struct OrganizationListFilters {
1790 pub limit: Option<usize>,
1791 pub after: Option<Uuid>,
1792 pub search: Option<String>,
1793 pub include_inactive: bool,
1794}
1795
1796#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, ToSchema, Default)]
1797#[serde(rename_all = "snake_case")]
1798pub enum GroupType {
1799 #[default]
1800 Standard,
1801 Team,
1802}
1803
1804impl GroupType {
1805 #[must_use]
1806 pub const fn as_str(&self) -> &'static str {
1807 match self {
1808 Self::Standard => "standard",
1809 Self::Team => "team",
1810 }
1811 }
1812}
1813
1814impl FromStr for GroupType {
1815 type Err = ();
1816
1817 fn from_str(value: &str) -> Result<Self, Self::Err> {
1818 match value {
1819 "standard" => Ok(Self::Standard),
1820 "team" => Ok(Self::Team),
1821 _ => Err(()),
1822 }
1823 }
1824}
1825
1826#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, ToSchema)]
1827#[serde(rename_all = "snake_case")]
1828pub enum GroupRole {
1829 Owner,
1830 Admin,
1831 Member,
1832 Viewer,
1833}
1834
1835impl GroupRole {
1836 #[must_use]
1837 pub const fn is_admin_like(&self) -> bool {
1838 matches!(self, Self::Owner | Self::Admin)
1839 }
1840
1841 #[must_use]
1842 pub const fn as_str(&self) -> &'static str {
1843 match self {
1844 Self::Owner => "owner",
1845 Self::Admin => "admin",
1846 Self::Member => "member",
1847 Self::Viewer => "viewer",
1848 }
1849 }
1850}
1851
1852impl FromStr for GroupRole {
1853 type Err = ();
1854
1855 fn from_str(value: &str) -> Result<Self, Self::Err> {
1856 match value {
1857 "owner" => Ok(Self::Owner),
1858 "admin" => Ok(Self::Admin),
1859 "member" => Ok(Self::Member),
1860 "viewer" => Ok(Self::Viewer),
1861 _ => Err(()),
1862 }
1863 }
1864}
1865
1866#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, ToSchema)]
1867#[serde(rename_all = "snake_case")]
1868pub enum GroupMemberStatus {
1869 Pending,
1870 Active,
1871 Suspended,
1872 Removed,
1873}
1874
1875impl GroupMemberStatus {
1876 #[must_use]
1877 pub const fn as_str(&self) -> &'static str {
1878 match self {
1879 Self::Pending => "pending",
1880 Self::Active => "active",
1881 Self::Suspended => "suspended",
1882 Self::Removed => "removed",
1883 }
1884 }
1885}
1886
1887impl FromStr for GroupMemberStatus {
1888 type Err = ();
1889
1890 fn from_str(value: &str) -> Result<Self, Self::Err> {
1891 match value {
1892 "pending" => Ok(Self::Pending),
1893 "active" => Ok(Self::Active),
1894 "suspended" => Ok(Self::Suspended),
1895 "removed" => Ok(Self::Removed),
1896 _ => Err(()),
1897 }
1898 }
1899}
1900
1901#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1902pub struct Group {
1903 pub id: Uuid,
1904 pub organization_id: Uuid,
1905 pub name: String,
1906 pub slug: String,
1907 pub group_type: GroupType,
1908 #[serde(skip_serializing_if = "Option::is_none")]
1909 pub description: Option<String>,
1910 #[serde(skip_serializing_if = "Option::is_none")]
1911 pub metadata: Option<HashMap<String, String>>,
1912 pub created_by: Uuid,
1913 pub created_at: DateTime<Utc>,
1914 pub updated_at: DateTime<Utc>,
1915 pub is_active: bool,
1916 pub member_count: usize,
1917}
1918
1919#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
1920pub struct CreateGroupRequest {
1921 #[validate(length(min = 3, max = 128))]
1922 pub name: String,
1923 #[validate(length(min = 3, max = 64))]
1924 pub slug: Option<String>,
1925 #[serde(default)]
1926 pub group_type: GroupType,
1927 #[validate(length(max = 1024))]
1928 pub description: Option<String>,
1929 pub metadata: Option<HashMap<String, String>>,
1930}
1931
1932#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
1933pub struct UpdateGroupRequest {
1934 #[validate(length(min = 3, max = 128))]
1935 pub name: Option<String>,
1936 #[validate(length(min = 3, max = 64))]
1937 pub slug: Option<Option<String>>,
1938 pub group_type: Option<GroupType>,
1939 #[validate(length(max = 1024))]
1940 pub description: Option<Option<String>>,
1941 pub metadata: Option<Option<HashMap<String, String>>>,
1942 pub is_active: Option<bool>,
1943}
1944
1945#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1946pub struct GroupSummary {
1947 #[serde(flatten)]
1948 pub group: Group,
1949}
1950
1951#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1952pub struct GroupListResponse {
1953 pub groups: Vec<GroupSummary>,
1954}
1955
1956#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1957pub struct GroupMember {
1958 pub user_id: Uuid,
1959 pub role: GroupRole,
1960 pub status: GroupMemberStatus,
1961 #[serde(skip_serializing_if = "Option::is_none")]
1962 pub invited_by: Option<Uuid>,
1963 #[serde(skip_serializing_if = "Option::is_none")]
1964 pub invited_at: Option<DateTime<Utc>>,
1965 #[serde(skip_serializing_if = "Option::is_none")]
1966 pub joined_at: Option<DateTime<Utc>>,
1967}
1968
1969#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
1970pub struct GroupMemberListResponse {
1971 pub members: Vec<GroupMember>,
1972}
1973
1974#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
1975pub struct AddGroupMemberRequest {
1976 pub user_id: Uuid,
1977 pub role: GroupRole,
1978}
1979
1980#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
1981pub struct UpdateGroupMemberRequest {
1982 pub role: Option<GroupRole>,
1983 pub status: Option<GroupMemberStatus>,
1984}
1985
1986#[derive(Debug, Clone)]
1987pub struct NewGroup {
1988 pub id: Uuid,
1989 pub organization_id: Uuid,
1990 pub name: String,
1991 pub slug: String,
1992 pub group_type: GroupType,
1993 pub description: Option<String>,
1994 pub metadata: Option<HashMap<String, String>>,
1995 pub created_by: Uuid,
1996 pub created_at: DateTime<Utc>,
1997 pub updated_at: DateTime<Utc>,
1998 pub is_active: bool,
1999}
2000
2001#[derive(Debug, Clone)]
2002pub struct GroupUpdate {
2003 pub name: Option<String>,
2004 pub slug: Option<Option<String>>,
2005 pub group_type: Option<GroupType>,
2006 pub description: Option<Option<String>>,
2007 pub metadata: Option<Option<HashMap<String, String>>>,
2008 pub is_active: Option<bool>,
2009 pub updated_at: DateTime<Utc>,
2010}
2011
2012#[derive(Debug, Clone)]
2013pub struct NewGroupMember {
2014 pub group_id: Uuid,
2015 pub user_id: Uuid,
2016 pub role: GroupRole,
2017 pub status: GroupMemberStatus,
2018 pub invited_by: Option<Uuid>,
2019 pub invited_at: Option<DateTime<Utc>>,
2020 pub joined_at: Option<DateTime<Utc>>,
2021}
2022
2023#[derive(Debug, Clone)]
2024pub struct GroupMemberUpdate {
2025 pub role: Option<GroupRole>,
2026 pub status: Option<GroupMemberStatus>,
2027 pub joined_at: Option<Option<DateTime<Utc>>>,
2028}
2029
2030#[derive(Debug, Clone, Default)]
2031pub struct GroupListFilters {
2032 pub organization_id: Uuid,
2033 pub group_type: Option<GroupType>,
2034 pub limit: Option<usize>,
2035 pub after: Option<Uuid>,
2036 pub search: Option<String>,
2037 pub include_inactive: bool,
2038}
2039
2040#[derive(Debug, Clone, Default)]
2041pub struct ApiKeyListFilters {
2042 pub role: Option<ApiKeyRole>,
2043 pub status: Option<ApiKeyStatus>,
2044 pub expires_before: Option<DateTime<Utc>>,
2045 pub created_by: Option<Uuid>,
2046 pub search: Option<String>,
2047 pub limit: Option<i64>,
2048}
2049
2050#[derive(Debug, Clone, Serialize, Deserialize, Default, ToSchema)]
2051pub struct ObjectMeta {
2052 #[serde(skip_serializing_if = "Option::is_none")]
2053 pub name: Option<String>,
2054 #[serde(skip_serializing_if = "Option::is_none")]
2055 pub namespace: Option<String>,
2056 #[serde(skip_serializing_if = "Option::is_none")]
2057 pub uid: Option<String>,
2058 #[serde(skip_serializing_if = "Option::is_none")]
2059 pub resource_version: Option<String>,
2060 #[serde(skip_serializing_if = "Option::is_none")]
2061 pub creation_timestamp: Option<DateTime<Utc>>,
2062 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
2063 pub labels: HashMap<String, String>,
2064 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
2065 pub annotations: HashMap<String, String>,
2066}
2067
2068#[derive(Debug, Clone, Serialize, Deserialize, Default, ToSchema)]
2069pub struct ListMeta {
2070 #[serde(skip_serializing_if = "Option::is_none")]
2071 pub resource_version: Option<String>,
2072 #[serde(rename = "continue", skip_serializing_if = "Option::is_none")]
2073 pub continue_token: Option<String>,
2074}
2075
2076#[derive(Debug, Clone, Serialize, Deserialize, Default, ToSchema)]
2077pub struct ResourceListOptions {
2078 #[serde(rename = "labelSelector", skip_serializing_if = "Option::is_none")]
2079 pub label_selector: Option<String>,
2080 #[serde(rename = "fieldSelector", skip_serializing_if = "Option::is_none")]
2081 pub field_selector: Option<String>,
2082 #[serde(skip_serializing_if = "Option::is_none")]
2083 pub limit: Option<usize>,
2084 #[serde(rename = "continue", skip_serializing_if = "Option::is_none")]
2085 pub continue_token: Option<String>,
2086}
2087
2088#[derive(Debug, Clone, Serialize, Deserialize, Default, ToSchema)]
2089pub struct LabelSelector {
2090 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
2091 pub match_labels: HashMap<String, String>,
2092 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2093 pub match_expressions: Vec<LabelSelectorRequirement>,
2094}
2095
2096#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2097pub struct LabelSelectorRequirement {
2098 pub key: String,
2099 pub operator: String,
2100 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2101 pub values: Vec<String>,
2102}
2103
2104#[derive(Debug, Clone, Serialize, Deserialize, Default, ToSchema)]
2105pub struct ObjectReference {
2106 #[serde(skip_serializing_if = "Option::is_none")]
2107 pub api_version: Option<String>,
2108 #[serde(skip_serializing_if = "Option::is_none")]
2109 pub kind: Option<String>,
2110 #[serde(skip_serializing_if = "Option::is_none")]
2111 pub name: Option<String>,
2112 #[serde(skip_serializing_if = "Option::is_none")]
2113 pub namespace: Option<String>,
2114 #[serde(skip_serializing_if = "Option::is_none")]
2115 pub uid: Option<String>,
2116}
2117
2118#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2119pub struct NamespaceStatus {
2120 #[serde(skip_serializing_if = "Option::is_none")]
2121 pub phase: Option<String>,
2122}
2123
2124#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2125pub struct Namespace {
2126 #[serde(skip_serializing_if = "Option::is_none")]
2127 pub api_version: Option<String>,
2128 #[serde(skip_serializing_if = "Option::is_none")]
2129 pub kind: Option<String>,
2130 pub metadata: ObjectMeta,
2131 #[serde(skip_serializing_if = "Option::is_none")]
2132 pub status: Option<NamespaceStatus>,
2133}
2134
2135#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2136pub struct NamespaceList {
2137 #[serde(skip_serializing_if = "Option::is_none")]
2138 pub api_version: Option<String>,
2139 #[serde(skip_serializing_if = "Option::is_none")]
2140 pub kind: Option<String>,
2141 #[serde(default)]
2142 pub metadata: ListMeta,
2143 pub items: Vec<Namespace>,
2144}
2145
2146#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2147pub struct Taint {
2148 pub key: String,
2149 #[serde(skip_serializing_if = "Option::is_none")]
2150 pub value: Option<String>,
2151 #[serde(skip_serializing_if = "Option::is_none")]
2152 pub effect: Option<String>,
2153 #[serde(skip_serializing_if = "Option::is_none")]
2154 pub time_added: Option<DateTime<Utc>>,
2155}
2156
2157#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2158pub struct NodeSpec {
2159 #[serde(skip_serializing_if = "Option::is_none")]
2160 pub unschedulable: Option<bool>,
2161 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2162 pub taints: Vec<Taint>,
2163}
2164
2165#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2166pub struct NodeResourceCapacity {
2167 #[serde(skip_serializing_if = "Option::is_none")]
2168 pub pods: Option<i32>,
2169 #[serde(skip_serializing_if = "Option::is_none")]
2170 pub cpu_millis: Option<u64>,
2171 #[serde(skip_serializing_if = "Option::is_none")]
2172 pub memory_mb: Option<u64>,
2173 #[serde(skip_serializing_if = "Option::is_none")]
2174 pub gpus: Option<u64>,
2175}
2176
2177#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2178pub struct NodeInventory {
2179 #[serde(skip_serializing_if = "Option::is_none")]
2180 pub capacity: Option<NodeResourceCapacity>,
2181 #[serde(skip_serializing_if = "Option::is_none")]
2182 pub allocatable: Option<NodeResourceCapacity>,
2183}
2184
2185#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2186pub struct NodeStatus {
2187 #[serde(skip_serializing_if = "Option::is_none")]
2188 pub ready: Option<bool>,
2189 #[serde(skip_serializing_if = "Option::is_none")]
2190 pub inventory: Option<NodeInventory>,
2191}
2192
2193#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2194pub struct Node {
2195 #[serde(skip_serializing_if = "Option::is_none")]
2196 pub api_version: Option<String>,
2197 #[serde(skip_serializing_if = "Option::is_none")]
2198 pub kind: Option<String>,
2199 pub metadata: ObjectMeta,
2200 #[serde(skip_serializing_if = "Option::is_none")]
2201 pub spec: Option<NodeSpec>,
2202 #[serde(skip_serializing_if = "Option::is_none")]
2203 pub status: Option<NodeStatus>,
2204}
2205
2206#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2207pub struct NodeList {
2208 #[serde(skip_serializing_if = "Option::is_none")]
2209 pub api_version: Option<String>,
2210 #[serde(skip_serializing_if = "Option::is_none")]
2211 pub kind: Option<String>,
2212 #[serde(default)]
2213 pub metadata: ListMeta,
2214 pub items: Vec<Node>,
2215}
2216
2217#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2218pub struct ConfigMap {
2219 #[serde(skip_serializing_if = "Option::is_none")]
2220 pub api_version: Option<String>,
2221 #[serde(skip_serializing_if = "Option::is_none")]
2222 pub kind: Option<String>,
2223 pub metadata: ObjectMeta,
2224 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
2225 pub data: HashMap<String, String>,
2226}
2227
2228#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2229pub struct ConfigMapList {
2230 #[serde(skip_serializing_if = "Option::is_none")]
2231 pub api_version: Option<String>,
2232 #[serde(skip_serializing_if = "Option::is_none")]
2233 pub kind: Option<String>,
2234 #[serde(default)]
2235 pub metadata: ListMeta,
2236 pub items: Vec<ConfigMap>,
2237}
2238
2239#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2240pub struct Secret {
2241 #[serde(skip_serializing_if = "Option::is_none")]
2242 pub api_version: Option<String>,
2243 #[serde(skip_serializing_if = "Option::is_none")]
2244 pub kind: Option<String>,
2245 pub metadata: ObjectMeta,
2246 #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
2247 pub secret_type: Option<String>,
2248 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
2249 pub data: HashMap<String, String>,
2250}
2251
2252#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2253pub struct SecretList {
2254 #[serde(skip_serializing_if = "Option::is_none")]
2255 pub api_version: Option<String>,
2256 #[serde(skip_serializing_if = "Option::is_none")]
2257 pub kind: Option<String>,
2258 #[serde(default)]
2259 pub metadata: ListMeta,
2260 pub items: Vec<Secret>,
2261}
2262
2263#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2264pub struct ServiceAccount {
2265 #[serde(skip_serializing_if = "Option::is_none")]
2266 pub api_version: Option<String>,
2267 #[serde(skip_serializing_if = "Option::is_none")]
2268 pub kind: Option<String>,
2269 pub metadata: ObjectMeta,
2270 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2271 pub secrets: Vec<ObjectReference>,
2272}
2273
2274#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2275pub struct ServiceAccountList {
2276 #[serde(skip_serializing_if = "Option::is_none")]
2277 pub api_version: Option<String>,
2278 #[serde(skip_serializing_if = "Option::is_none")]
2279 pub kind: Option<String>,
2280 #[serde(default)]
2281 pub metadata: ListMeta,
2282 pub items: Vec<ServiceAccount>,
2283}
2284
2285#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2286pub struct ServicePort {
2287 #[serde(skip_serializing_if = "Option::is_none")]
2288 pub name: Option<String>,
2289 pub port: u16,
2290 #[serde(skip_serializing_if = "Option::is_none")]
2291 pub target_port: Option<String>,
2292 #[serde(skip_serializing_if = "Option::is_none")]
2293 pub protocol: Option<String>,
2294}
2295
2296#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2297pub struct ServiceSpec {
2298 #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
2299 pub service_type: Option<String>,
2300 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
2301 pub selector: HashMap<String, String>,
2302 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2303 pub ports: Vec<ServicePort>,
2304}
2305
2306#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2307pub struct Service {
2308 #[serde(skip_serializing_if = "Option::is_none")]
2309 pub api_version: Option<String>,
2310 #[serde(skip_serializing_if = "Option::is_none")]
2311 pub kind: Option<String>,
2312 pub metadata: ObjectMeta,
2313 #[serde(skip_serializing_if = "Option::is_none")]
2314 pub spec: Option<ServiceSpec>,
2315 #[serde(skip_serializing_if = "Option::is_none")]
2316 pub status: Option<HashMap<String, Value>>,
2317}
2318
2319#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2320pub struct ServiceList {
2321 #[serde(skip_serializing_if = "Option::is_none")]
2322 pub api_version: Option<String>,
2323 #[serde(skip_serializing_if = "Option::is_none")]
2324 pub kind: Option<String>,
2325 #[serde(default)]
2326 pub metadata: ListMeta,
2327 pub items: Vec<Service>,
2328}
2329
2330#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2331pub struct EndpointAddress {
2332 pub ip: String,
2333 #[serde(skip_serializing_if = "Option::is_none")]
2334 pub target_ref: Option<ObjectReference>,
2335}
2336
2337#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2338pub struct EndpointPort {
2339 #[serde(skip_serializing_if = "Option::is_none")]
2340 pub name: Option<String>,
2341 pub port: u16,
2342 #[serde(skip_serializing_if = "Option::is_none")]
2343 pub protocol: Option<String>,
2344}
2345
2346#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2347pub struct EndpointSubset {
2348 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2349 pub addresses: Vec<EndpointAddress>,
2350 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2351 pub ports: Vec<EndpointPort>,
2352}
2353
2354#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2355pub struct Endpoints {
2356 #[serde(skip_serializing_if = "Option::is_none")]
2357 pub api_version: Option<String>,
2358 #[serde(skip_serializing_if = "Option::is_none")]
2359 pub kind: Option<String>,
2360 pub metadata: ObjectMeta,
2361 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2362 pub subsets: Vec<EndpointSubset>,
2363}
2364
2365#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2366pub struct EndpointsList {
2367 #[serde(skip_serializing_if = "Option::is_none")]
2368 pub api_version: Option<String>,
2369 #[serde(skip_serializing_if = "Option::is_none")]
2370 pub kind: Option<String>,
2371 #[serde(default)]
2372 pub metadata: ListMeta,
2373 pub items: Vec<Endpoints>,
2374}
2375
2376#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2377pub struct EndpointSlicePort {
2378 #[serde(skip_serializing_if = "Option::is_none")]
2379 pub name: Option<String>,
2380 #[serde(skip_serializing_if = "Option::is_none")]
2381 pub port: Option<u16>,
2382 #[serde(skip_serializing_if = "Option::is_none")]
2383 pub protocol: Option<String>,
2384}
2385
2386#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2387pub struct EndpointSliceEndpoint {
2388 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2389 pub addresses: Vec<String>,
2390 #[serde(skip_serializing_if = "Option::is_none")]
2391 pub target_ref: Option<ObjectReference>,
2392 #[serde(skip_serializing_if = "Option::is_none")]
2393 pub conditions: Option<HashMap<String, bool>>,
2394}
2395
2396#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2397pub struct EndpointSlice {
2398 #[serde(skip_serializing_if = "Option::is_none")]
2399 pub api_version: Option<String>,
2400 #[serde(skip_serializing_if = "Option::is_none")]
2401 pub kind: Option<String>,
2402 pub metadata: ObjectMeta,
2403 pub address_type: String,
2404 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2405 pub endpoints: Vec<EndpointSliceEndpoint>,
2406 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2407 pub ports: Vec<EndpointSlicePort>,
2408}
2409
2410#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2411pub struct EndpointSliceList {
2412 #[serde(skip_serializing_if = "Option::is_none")]
2413 pub api_version: Option<String>,
2414 #[serde(skip_serializing_if = "Option::is_none")]
2415 pub kind: Option<String>,
2416 #[serde(default)]
2417 pub metadata: ListMeta,
2418 pub items: Vec<EndpointSlice>,
2419}
2420
2421#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2422pub struct WebhookServiceReference {
2423 pub name: String,
2424 pub namespace: String,
2425 #[serde(skip_serializing_if = "Option::is_none")]
2426 pub path: Option<String>,
2427}
2428
2429#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2430pub struct WebhookClientConfig {
2431 #[serde(skip_serializing_if = "Option::is_none")]
2432 pub url: Option<String>,
2433 #[serde(skip_serializing_if = "Option::is_none")]
2434 pub service: Option<WebhookServiceReference>,
2435 #[serde(skip_serializing_if = "Option::is_none")]
2436 pub ca_bundle: Option<String>,
2437}
2438
2439#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2440pub struct WebhookRule {
2441 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2442 pub api_groups: Vec<String>,
2443 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2444 pub api_versions: Vec<String>,
2445 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2446 pub resources: Vec<String>,
2447 #[serde(skip_serializing_if = "Option::is_none")]
2448 pub scope: Option<String>,
2449}
2450
2451#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2452pub struct WebhookRuleWithOperations {
2453 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2454 pub operations: Vec<String>,
2455 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2456 pub api_groups: Vec<String>,
2457 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2458 pub api_versions: Vec<String>,
2459 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2460 pub resources: Vec<String>,
2461 #[serde(skip_serializing_if = "Option::is_none")]
2462 pub scope: Option<String>,
2463}
2464
2465#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2466pub struct Webhook {
2467 pub name: String,
2468 pub client_config: WebhookClientConfig,
2469 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2470 pub rules: Vec<WebhookRuleWithOperations>,
2471 #[serde(skip_serializing_if = "Option::is_none")]
2472 pub failure_policy: Option<String>,
2473 #[serde(skip_serializing_if = "Option::is_none")]
2474 pub match_policy: Option<String>,
2475 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
2476 pub namespace_selector: HashMap<String, Value>,
2477 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
2478 pub object_selector: HashMap<String, Value>,
2479 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2480 pub admission_review_versions: Vec<String>,
2481 #[serde(skip_serializing_if = "Option::is_none")]
2482 pub side_effects: Option<String>,
2483 #[serde(skip_serializing_if = "Option::is_none")]
2484 pub timeout_seconds: Option<u32>,
2485}
2486
2487#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2488pub struct MutatingWebhookConfiguration {
2489 #[serde(skip_serializing_if = "Option::is_none")]
2490 pub api_version: Option<String>,
2491 #[serde(skip_serializing_if = "Option::is_none")]
2492 pub kind: Option<String>,
2493 pub metadata: ObjectMeta,
2494 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2495 pub webhooks: Vec<Webhook>,
2496}
2497
2498#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2499pub struct MutatingWebhookConfigurationList {
2500 #[serde(skip_serializing_if = "Option::is_none")]
2501 pub api_version: Option<String>,
2502 #[serde(skip_serializing_if = "Option::is_none")]
2503 pub kind: Option<String>,
2504 #[serde(default)]
2505 pub metadata: ListMeta,
2506 pub items: Vec<MutatingWebhookConfiguration>,
2507}
2508
2509#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2510pub struct ValidatingWebhookConfiguration {
2511 #[serde(skip_serializing_if = "Option::is_none")]
2512 pub api_version: Option<String>,
2513 #[serde(skip_serializing_if = "Option::is_none")]
2514 pub kind: Option<String>,
2515 pub metadata: ObjectMeta,
2516 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2517 pub webhooks: Vec<Webhook>,
2518}
2519
2520#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2521pub struct ValidatingWebhookConfigurationList {
2522 #[serde(skip_serializing_if = "Option::is_none")]
2523 pub api_version: Option<String>,
2524 #[serde(skip_serializing_if = "Option::is_none")]
2525 pub kind: Option<String>,
2526 #[serde(default)]
2527 pub metadata: ListMeta,
2528 pub items: Vec<ValidatingWebhookConfiguration>,
2529}
2530
2531#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2532pub struct CustomResourceDefinition {
2533 #[serde(skip_serializing_if = "Option::is_none")]
2534 pub api_version: Option<String>,
2535 #[serde(skip_serializing_if = "Option::is_none")]
2536 pub kind: Option<String>,
2537 pub metadata: ObjectMeta,
2538 #[serde(skip_serializing_if = "Option::is_none")]
2539 pub spec: Option<HashMap<String, Value>>,
2540 #[serde(skip_serializing_if = "Option::is_none")]
2541 pub status: Option<HashMap<String, Value>>,
2542}
2543
2544#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2545pub struct CustomResourceDefinitionList {
2546 #[serde(skip_serializing_if = "Option::is_none")]
2547 pub api_version: Option<String>,
2548 #[serde(skip_serializing_if = "Option::is_none")]
2549 pub kind: Option<String>,
2550 #[serde(default)]
2551 pub metadata: ListMeta,
2552 pub items: Vec<CustomResourceDefinition>,
2553}
2554
2555#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2556pub struct ResourceQuotaSpec {
2557 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
2558 pub hard: HashMap<String, String>,
2559}
2560
2561#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2562pub struct ResourceQuotaStatus {
2563 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
2564 pub hard: HashMap<String, String>,
2565 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
2566 pub used: HashMap<String, String>,
2567}
2568
2569#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2570pub struct ResourceQuota {
2571 #[serde(skip_serializing_if = "Option::is_none")]
2572 pub api_version: Option<String>,
2573 #[serde(skip_serializing_if = "Option::is_none")]
2574 pub kind: Option<String>,
2575 pub metadata: ObjectMeta,
2576 #[serde(skip_serializing_if = "Option::is_none")]
2577 pub spec: Option<ResourceQuotaSpec>,
2578 #[serde(skip_serializing_if = "Option::is_none")]
2579 pub status: Option<ResourceQuotaStatus>,
2580}
2581
2582#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2583pub struct ResourceQuotaList {
2584 #[serde(skip_serializing_if = "Option::is_none")]
2585 pub api_version: Option<String>,
2586 #[serde(skip_serializing_if = "Option::is_none")]
2587 pub kind: Option<String>,
2588 #[serde(default)]
2589 pub metadata: ListMeta,
2590 pub items: Vec<ResourceQuota>,
2591}
2592
2593#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2594pub struct LimitRangeItem {
2595 #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
2596 pub limit_type: Option<String>,
2597 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
2598 pub max: HashMap<String, String>,
2599 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
2600 pub min: HashMap<String, String>,
2601 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
2602 pub default: HashMap<String, String>,
2603 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
2604 pub default_request: HashMap<String, String>,
2605 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
2606 pub max_limit_request_ratio: HashMap<String, String>,
2607}
2608
2609#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2610pub struct LimitRangeSpec {
2611 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2612 pub limits: Vec<LimitRangeItem>,
2613}
2614
2615#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2616pub struct LimitRange {
2617 #[serde(skip_serializing_if = "Option::is_none")]
2618 pub api_version: Option<String>,
2619 #[serde(skip_serializing_if = "Option::is_none")]
2620 pub kind: Option<String>,
2621 pub metadata: ObjectMeta,
2622 #[serde(skip_serializing_if = "Option::is_none")]
2623 pub spec: Option<LimitRangeSpec>,
2624}
2625
2626#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2627pub struct LimitRangeList {
2628 #[serde(skip_serializing_if = "Option::is_none")]
2629 pub api_version: Option<String>,
2630 #[serde(skip_serializing_if = "Option::is_none")]
2631 pub kind: Option<String>,
2632 #[serde(default)]
2633 pub metadata: ListMeta,
2634 pub items: Vec<LimitRange>,
2635}
2636
2637#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2638pub struct PodDisruptionBudgetSpec {
2639 #[serde(skip_serializing_if = "Option::is_none")]
2640 pub min_available: Option<String>,
2641 #[serde(skip_serializing_if = "Option::is_none")]
2642 pub max_unavailable: Option<String>,
2643 #[serde(skip_serializing_if = "Option::is_none")]
2644 pub selector: Option<LabelSelector>,
2645}
2646
2647#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2648pub struct PodDisruptionBudgetStatus {
2649 #[serde(skip_serializing_if = "Option::is_none")]
2650 pub current_healthy: Option<i32>,
2651 #[serde(skip_serializing_if = "Option::is_none")]
2652 pub desired_healthy: Option<i32>,
2653 #[serde(skip_serializing_if = "Option::is_none")]
2654 pub disruptions_allowed: Option<i32>,
2655}
2656
2657#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2658pub struct PodDisruptionBudget {
2659 #[serde(skip_serializing_if = "Option::is_none")]
2660 pub api_version: Option<String>,
2661 #[serde(skip_serializing_if = "Option::is_none")]
2662 pub kind: Option<String>,
2663 pub metadata: ObjectMeta,
2664 #[serde(skip_serializing_if = "Option::is_none")]
2665 pub spec: Option<PodDisruptionBudgetSpec>,
2666 #[serde(skip_serializing_if = "Option::is_none")]
2667 pub status: Option<PodDisruptionBudgetStatus>,
2668}
2669
2670#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2671pub struct PodDisruptionBudgetList {
2672 #[serde(skip_serializing_if = "Option::is_none")]
2673 pub api_version: Option<String>,
2674 #[serde(skip_serializing_if = "Option::is_none")]
2675 pub kind: Option<String>,
2676 #[serde(default)]
2677 pub metadata: ListMeta,
2678 pub items: Vec<PodDisruptionBudget>,
2679}
2680
2681#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2682pub struct PriorityClass {
2683 #[serde(skip_serializing_if = "Option::is_none")]
2684 pub api_version: Option<String>,
2685 #[serde(skip_serializing_if = "Option::is_none")]
2686 pub kind: Option<String>,
2687 pub metadata: ObjectMeta,
2688 pub value: i32,
2689 #[serde(skip_serializing_if = "Option::is_none")]
2690 pub global_default: Option<bool>,
2691 #[serde(skip_serializing_if = "Option::is_none")]
2692 pub description: Option<String>,
2693 #[serde(skip_serializing_if = "Option::is_none")]
2694 pub preemption_policy: Option<String>,
2695}
2696
2697#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2698pub struct PriorityClassList {
2699 #[serde(skip_serializing_if = "Option::is_none")]
2700 pub api_version: Option<String>,
2701 #[serde(skip_serializing_if = "Option::is_none")]
2702 pub kind: Option<String>,
2703 #[serde(default)]
2704 pub metadata: ListMeta,
2705 pub items: Vec<PriorityClass>,
2706}
2707
2708#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2709pub struct NetworkPolicySpec {
2710 #[serde(skip_serializing_if = "Option::is_none")]
2711 pub pod_selector: Option<LabelSelector>,
2712 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2713 pub policy_types: Vec<String>,
2714 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2715 pub ingress: Vec<Value>,
2716 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2717 pub egress: Vec<Value>,
2718}
2719
2720#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2721pub struct NetworkPolicy {
2722 #[serde(skip_serializing_if = "Option::is_none")]
2723 pub api_version: Option<String>,
2724 #[serde(skip_serializing_if = "Option::is_none")]
2725 pub kind: Option<String>,
2726 pub metadata: ObjectMeta,
2727 #[serde(skip_serializing_if = "Option::is_none")]
2728 pub spec: Option<NetworkPolicySpec>,
2729}
2730
2731#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2732pub struct NetworkPolicyList {
2733 #[serde(skip_serializing_if = "Option::is_none")]
2734 pub api_version: Option<String>,
2735 #[serde(skip_serializing_if = "Option::is_none")]
2736 pub kind: Option<String>,
2737 #[serde(default)]
2738 pub metadata: ListMeta,
2739 pub items: Vec<NetworkPolicy>,
2740}
2741
2742#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2743pub struct IngressSpec {
2744 #[serde(skip_serializing_if = "Option::is_none")]
2745 pub ingress_class_name: Option<String>,
2746 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2747 pub rules: Vec<Value>,
2748 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2749 pub tls: Vec<Value>,
2750}
2751
2752#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2753pub struct Ingress {
2754 #[serde(skip_serializing_if = "Option::is_none")]
2755 pub api_version: Option<String>,
2756 #[serde(skip_serializing_if = "Option::is_none")]
2757 pub kind: Option<String>,
2758 pub metadata: ObjectMeta,
2759 #[serde(skip_serializing_if = "Option::is_none")]
2760 pub spec: Option<IngressSpec>,
2761 #[serde(skip_serializing_if = "Option::is_none")]
2762 pub status: Option<HashMap<String, Value>>,
2763}
2764
2765#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2766pub struct IngressList {
2767 #[serde(skip_serializing_if = "Option::is_none")]
2768 pub api_version: Option<String>,
2769 #[serde(skip_serializing_if = "Option::is_none")]
2770 pub kind: Option<String>,
2771 #[serde(default)]
2772 pub metadata: ListMeta,
2773 pub items: Vec<Ingress>,
2774}
2775
2776#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2777pub struct IngressClassSpec {
2778 #[serde(skip_serializing_if = "Option::is_none")]
2779 pub controller: Option<String>,
2780 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
2781 pub parameters: HashMap<String, Value>,
2782}
2783
2784#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2785pub struct IngressClass {
2786 #[serde(skip_serializing_if = "Option::is_none")]
2787 pub api_version: Option<String>,
2788 #[serde(skip_serializing_if = "Option::is_none")]
2789 pub kind: Option<String>,
2790 pub metadata: ObjectMeta,
2791 #[serde(skip_serializing_if = "Option::is_none")]
2792 pub spec: Option<IngressClassSpec>,
2793}
2794
2795#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2796pub struct IngressClassList {
2797 #[serde(skip_serializing_if = "Option::is_none")]
2798 pub api_version: Option<String>,
2799 #[serde(skip_serializing_if = "Option::is_none")]
2800 pub kind: Option<String>,
2801 #[serde(default)]
2802 pub metadata: ListMeta,
2803 pub items: Vec<IngressClass>,
2804}
2805
2806#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2807pub struct GatewayClassSpec {
2808 #[serde(skip_serializing_if = "Option::is_none")]
2809 pub controller_name: Option<String>,
2810 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
2811 pub parameters_ref: HashMap<String, Value>,
2812}
2813
2814#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2815pub struct GatewayClass {
2816 #[serde(skip_serializing_if = "Option::is_none")]
2817 pub api_version: Option<String>,
2818 #[serde(skip_serializing_if = "Option::is_none")]
2819 pub kind: Option<String>,
2820 pub metadata: ObjectMeta,
2821 #[serde(skip_serializing_if = "Option::is_none")]
2822 pub spec: Option<GatewayClassSpec>,
2823 #[serde(skip_serializing_if = "Option::is_none")]
2824 pub status: Option<HashMap<String, Value>>,
2825}
2826
2827#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2828pub struct GatewayClassList {
2829 #[serde(skip_serializing_if = "Option::is_none")]
2830 pub api_version: Option<String>,
2831 #[serde(skip_serializing_if = "Option::is_none")]
2832 pub kind: Option<String>,
2833 #[serde(default)]
2834 pub metadata: ListMeta,
2835 pub items: Vec<GatewayClass>,
2836}
2837
2838#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2839pub struct GatewaySpec {
2840 #[serde(skip_serializing_if = "Option::is_none")]
2841 pub gateway_class_name: Option<String>,
2842 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2843 pub listeners: Vec<Value>,
2844}
2845
2846#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2847pub struct Gateway {
2848 #[serde(skip_serializing_if = "Option::is_none")]
2849 pub api_version: Option<String>,
2850 #[serde(skip_serializing_if = "Option::is_none")]
2851 pub kind: Option<String>,
2852 pub metadata: ObjectMeta,
2853 #[serde(skip_serializing_if = "Option::is_none")]
2854 pub spec: Option<GatewaySpec>,
2855 #[serde(skip_serializing_if = "Option::is_none")]
2856 pub status: Option<HashMap<String, Value>>,
2857}
2858
2859#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2860pub struct GatewayList {
2861 #[serde(skip_serializing_if = "Option::is_none")]
2862 pub api_version: Option<String>,
2863 #[serde(skip_serializing_if = "Option::is_none")]
2864 pub kind: Option<String>,
2865 #[serde(default)]
2866 pub metadata: ListMeta,
2867 pub items: Vec<Gateway>,
2868}
2869
2870#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2871pub struct HTTPRouteSpec {
2872 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2873 pub parent_refs: Vec<Value>,
2874 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2875 pub hostnames: Vec<String>,
2876 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2877 pub rules: Vec<Value>,
2878}
2879
2880#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2881pub struct HTTPRoute {
2882 #[serde(skip_serializing_if = "Option::is_none")]
2883 pub api_version: Option<String>,
2884 #[serde(skip_serializing_if = "Option::is_none")]
2885 pub kind: Option<String>,
2886 pub metadata: ObjectMeta,
2887 #[serde(skip_serializing_if = "Option::is_none")]
2888 pub spec: Option<HTTPRouteSpec>,
2889 #[serde(skip_serializing_if = "Option::is_none")]
2890 pub status: Option<HashMap<String, Value>>,
2891}
2892
2893#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2894pub struct HTTPRouteList {
2895 #[serde(skip_serializing_if = "Option::is_none")]
2896 pub api_version: Option<String>,
2897 #[serde(skip_serializing_if = "Option::is_none")]
2898 pub kind: Option<String>,
2899 #[serde(default)]
2900 pub metadata: ListMeta,
2901 pub items: Vec<HTTPRoute>,
2902}
2903
2904#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2905pub struct TCPRouteSpec {
2906 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2907 pub parent_refs: Vec<Value>,
2908 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2909 pub rules: Vec<Value>,
2910}
2911
2912#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2913pub struct TCPRoute {
2914 #[serde(skip_serializing_if = "Option::is_none")]
2915 pub api_version: Option<String>,
2916 #[serde(skip_serializing_if = "Option::is_none")]
2917 pub kind: Option<String>,
2918 pub metadata: ObjectMeta,
2919 #[serde(skip_serializing_if = "Option::is_none")]
2920 pub spec: Option<TCPRouteSpec>,
2921 #[serde(skip_serializing_if = "Option::is_none")]
2922 pub status: Option<HashMap<String, Value>>,
2923}
2924
2925#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2926pub struct TCPRouteList {
2927 #[serde(skip_serializing_if = "Option::is_none")]
2928 pub api_version: Option<String>,
2929 #[serde(skip_serializing_if = "Option::is_none")]
2930 pub kind: Option<String>,
2931 #[serde(default)]
2932 pub metadata: ListMeta,
2933 pub items: Vec<TCPRoute>,
2934}
2935
2936#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2937pub struct TLSRouteSpec {
2938 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2939 pub parent_refs: Vec<Value>,
2940 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2941 pub rules: Vec<Value>,
2942}
2943
2944#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2945pub struct TLSRoute {
2946 #[serde(skip_serializing_if = "Option::is_none")]
2947 pub api_version: Option<String>,
2948 #[serde(skip_serializing_if = "Option::is_none")]
2949 pub kind: Option<String>,
2950 pub metadata: ObjectMeta,
2951 #[serde(skip_serializing_if = "Option::is_none")]
2952 pub spec: Option<TLSRouteSpec>,
2953 #[serde(skip_serializing_if = "Option::is_none")]
2954 pub status: Option<HashMap<String, Value>>,
2955}
2956
2957#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2958pub struct TLSRouteList {
2959 #[serde(skip_serializing_if = "Option::is_none")]
2960 pub api_version: Option<String>,
2961 #[serde(skip_serializing_if = "Option::is_none")]
2962 pub kind: Option<String>,
2963 #[serde(default)]
2964 pub metadata: ListMeta,
2965 pub items: Vec<TLSRoute>,
2966}
2967
2968#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2969pub struct UDPRouteSpec {
2970 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2971 pub parent_refs: Vec<Value>,
2972 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2973 pub rules: Vec<Value>,
2974}
2975
2976#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2977pub struct UDPRoute {
2978 #[serde(skip_serializing_if = "Option::is_none")]
2979 pub api_version: Option<String>,
2980 #[serde(skip_serializing_if = "Option::is_none")]
2981 pub kind: Option<String>,
2982 pub metadata: ObjectMeta,
2983 #[serde(skip_serializing_if = "Option::is_none")]
2984 pub spec: Option<UDPRouteSpec>,
2985 #[serde(skip_serializing_if = "Option::is_none")]
2986 pub status: Option<HashMap<String, Value>>,
2987}
2988
2989#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
2990pub struct UDPRouteList {
2991 #[serde(skip_serializing_if = "Option::is_none")]
2992 pub api_version: Option<String>,
2993 #[serde(skip_serializing_if = "Option::is_none")]
2994 pub kind: Option<String>,
2995 #[serde(default)]
2996 pub metadata: ListMeta,
2997 pub items: Vec<UDPRoute>,
2998}
2999
3000#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3001pub struct GRPCRouteSpec {
3002 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3003 pub parent_refs: Vec<Value>,
3004 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3005 pub rules: Vec<Value>,
3006}
3007
3008#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3009pub struct GRPCRoute {
3010 #[serde(skip_serializing_if = "Option::is_none")]
3011 pub api_version: Option<String>,
3012 #[serde(skip_serializing_if = "Option::is_none")]
3013 pub kind: Option<String>,
3014 pub metadata: ObjectMeta,
3015 #[serde(skip_serializing_if = "Option::is_none")]
3016 pub spec: Option<GRPCRouteSpec>,
3017 #[serde(skip_serializing_if = "Option::is_none")]
3018 pub status: Option<HashMap<String, Value>>,
3019}
3020
3021#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3022pub struct GRPCRouteList {
3023 #[serde(skip_serializing_if = "Option::is_none")]
3024 pub api_version: Option<String>,
3025 #[serde(skip_serializing_if = "Option::is_none")]
3026 pub kind: Option<String>,
3027 #[serde(default)]
3028 pub metadata: ListMeta,
3029 pub items: Vec<GRPCRoute>,
3030}
3031
3032#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3033pub struct ReferenceGrantSpec {
3034 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3035 pub from: Vec<Value>,
3036 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3037 pub to: Vec<Value>,
3038}
3039
3040#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3041pub struct ReferenceGrant {
3042 #[serde(skip_serializing_if = "Option::is_none")]
3043 pub api_version: Option<String>,
3044 #[serde(skip_serializing_if = "Option::is_none")]
3045 pub kind: Option<String>,
3046 pub metadata: ObjectMeta,
3047 #[serde(skip_serializing_if = "Option::is_none")]
3048 pub spec: Option<ReferenceGrantSpec>,
3049}
3050
3051#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3052pub struct ReferenceGrantList {
3053 #[serde(skip_serializing_if = "Option::is_none")]
3054 pub api_version: Option<String>,
3055 #[serde(skip_serializing_if = "Option::is_none")]
3056 pub kind: Option<String>,
3057 #[serde(default)]
3058 pub metadata: ListMeta,
3059 pub items: Vec<ReferenceGrant>,
3060}
3061
3062#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3063pub struct StorageClass {
3064 #[serde(skip_serializing_if = "Option::is_none")]
3065 pub api_version: Option<String>,
3066 #[serde(skip_serializing_if = "Option::is_none")]
3067 pub kind: Option<String>,
3068 pub metadata: ObjectMeta,
3069 pub provisioner: String,
3070 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
3071 pub parameters: HashMap<String, String>,
3072 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3073 pub mount_options: Vec<String>,
3074 #[serde(skip_serializing_if = "Option::is_none")]
3075 pub reclaim_policy: Option<String>,
3076 #[serde(skip_serializing_if = "Option::is_none")]
3077 pub volume_binding_mode: Option<String>,
3078 #[serde(skip_serializing_if = "Option::is_none")]
3079 pub allow_volume_expansion: Option<bool>,
3080}
3081
3082#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3083pub struct StorageClassList {
3084 #[serde(skip_serializing_if = "Option::is_none")]
3085 pub api_version: Option<String>,
3086 #[serde(skip_serializing_if = "Option::is_none")]
3087 pub kind: Option<String>,
3088 #[serde(default)]
3089 pub metadata: ListMeta,
3090 pub items: Vec<StorageClass>,
3091}
3092
3093#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3094pub struct CsiDriverSpec {
3095 #[serde(skip_serializing_if = "Option::is_none")]
3096 pub attach_required: Option<bool>,
3097 #[serde(skip_serializing_if = "Option::is_none")]
3098 pub pod_info_on_mount: Option<bool>,
3099 #[serde(skip_serializing_if = "Option::is_none")]
3100 pub fs_group_policy: Option<String>,
3101 #[serde(skip_serializing_if = "Option::is_none")]
3102 pub storage_capacity: Option<bool>,
3103 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3104 pub volume_lifecycle_modes: Vec<String>,
3105}
3106
3107#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3108pub struct CsiDriver {
3109 #[serde(skip_serializing_if = "Option::is_none")]
3110 pub api_version: Option<String>,
3111 #[serde(skip_serializing_if = "Option::is_none")]
3112 pub kind: Option<String>,
3113 pub metadata: ObjectMeta,
3114 #[serde(skip_serializing_if = "Option::is_none")]
3115 pub spec: Option<CsiDriverSpec>,
3116}
3117
3118#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3119pub struct CsiDriverList {
3120 #[serde(skip_serializing_if = "Option::is_none")]
3121 pub api_version: Option<String>,
3122 #[serde(skip_serializing_if = "Option::is_none")]
3123 pub kind: Option<String>,
3124 #[serde(default)]
3125 pub metadata: ListMeta,
3126 pub items: Vec<CsiDriver>,
3127}
3128
3129#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3130pub struct PersistentVolumeSpec {
3131 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
3132 pub capacity: HashMap<String, String>,
3133 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3134 pub access_modes: Vec<String>,
3135 #[serde(skip_serializing_if = "Option::is_none")]
3136 pub storage_class_name: Option<String>,
3137 #[serde(skip_serializing_if = "Option::is_none")]
3138 pub claim_ref: Option<ObjectReference>,
3139 #[serde(skip_serializing_if = "Option::is_none")]
3140 pub volume_mode: Option<String>,
3141 #[serde(skip_serializing_if = "Option::is_none")]
3142 pub persistent_volume_reclaim_policy: Option<String>,
3143 #[serde(skip_serializing_if = "Option::is_none")]
3144 pub volume_source: Option<Value>,
3145}
3146
3147#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3148pub struct PersistentVolumeStatus {
3149 #[serde(skip_serializing_if = "Option::is_none")]
3150 pub phase: Option<String>,
3151 #[serde(skip_serializing_if = "Option::is_none")]
3152 pub message: Option<String>,
3153 #[serde(skip_serializing_if = "Option::is_none")]
3154 pub reason: Option<String>,
3155 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
3156 pub capacity: HashMap<String, String>,
3157}
3158
3159#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3160pub struct PersistentVolume {
3161 #[serde(skip_serializing_if = "Option::is_none")]
3162 pub api_version: Option<String>,
3163 #[serde(skip_serializing_if = "Option::is_none")]
3164 pub kind: Option<String>,
3165 pub metadata: ObjectMeta,
3166 #[serde(skip_serializing_if = "Option::is_none")]
3167 pub spec: Option<PersistentVolumeSpec>,
3168 #[serde(skip_serializing_if = "Option::is_none")]
3169 pub status: Option<PersistentVolumeStatus>,
3170}
3171
3172#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3173pub struct PersistentVolumeList {
3174 #[serde(skip_serializing_if = "Option::is_none")]
3175 pub api_version: Option<String>,
3176 #[serde(skip_serializing_if = "Option::is_none")]
3177 pub kind: Option<String>,
3178 #[serde(default)]
3179 pub metadata: ListMeta,
3180 pub items: Vec<PersistentVolume>,
3181}
3182
3183#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3184pub struct PersistentVolumeClaimSpec {
3185 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3186 pub access_modes: Vec<String>,
3187 #[serde(skip_serializing_if = "Option::is_none")]
3188 pub storage_class_name: Option<String>,
3189 #[serde(skip_serializing_if = "Option::is_none")]
3190 pub volume_name: Option<String>,
3191 #[serde(skip_serializing_if = "Option::is_none")]
3192 pub resources: Option<ResourceRequirements>,
3193 #[serde(skip_serializing_if = "Option::is_none")]
3194 pub volume_mode: Option<String>,
3195 #[serde(skip_serializing_if = "Option::is_none")]
3196 pub selector: Option<LabelSelector>,
3197}
3198
3199#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3200pub struct PersistentVolumeClaimStatus {
3201 #[serde(skip_serializing_if = "Option::is_none")]
3202 pub phase: Option<String>,
3203 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3204 pub access_modes: Vec<String>,
3205 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
3206 pub capacity: HashMap<String, String>,
3207 #[serde(skip_serializing_if = "Option::is_none")]
3208 pub volume_name: Option<String>,
3209}
3210
3211#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3212pub struct PersistentVolumeClaim {
3213 #[serde(skip_serializing_if = "Option::is_none")]
3214 pub api_version: Option<String>,
3215 #[serde(skip_serializing_if = "Option::is_none")]
3216 pub kind: Option<String>,
3217 pub metadata: ObjectMeta,
3218 #[serde(skip_serializing_if = "Option::is_none")]
3219 pub spec: Option<PersistentVolumeClaimSpec>,
3220 #[serde(skip_serializing_if = "Option::is_none")]
3221 pub status: Option<PersistentVolumeClaimStatus>,
3222}
3223
3224#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3225pub struct PersistentVolumeClaimList {
3226 #[serde(skip_serializing_if = "Option::is_none")]
3227 pub api_version: Option<String>,
3228 #[serde(skip_serializing_if = "Option::is_none")]
3229 pub kind: Option<String>,
3230 #[serde(default)]
3231 pub metadata: ListMeta,
3232 pub items: Vec<PersistentVolumeClaim>,
3233}
3234
3235#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3236pub struct VolumeSnapshotSource {
3237 #[serde(skip_serializing_if = "Option::is_none")]
3238 pub persistent_volume_claim_name: Option<String>,
3239 #[serde(skip_serializing_if = "Option::is_none")]
3240 pub volume_snapshot_content_name: Option<String>,
3241}
3242
3243#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3244pub struct VolumeSnapshotSpec {
3245 #[serde(skip_serializing_if = "Option::is_none")]
3246 pub volume_snapshot_class_name: Option<String>,
3247 pub source: VolumeSnapshotSource,
3248}
3249
3250#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3251pub struct VolumeSnapshotStatus {
3252 #[serde(skip_serializing_if = "Option::is_none")]
3253 pub ready_to_use: Option<bool>,
3254 #[serde(skip_serializing_if = "Option::is_none")]
3255 pub creation_time: Option<DateTime<Utc>>,
3256 #[serde(skip_serializing_if = "Option::is_none")]
3257 pub restore_size: Option<String>,
3258 #[serde(skip_serializing_if = "Option::is_none")]
3259 pub bound_volume_snapshot_content_name: Option<String>,
3260}
3261
3262#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3263pub struct VolumeSnapshot {
3264 #[serde(skip_serializing_if = "Option::is_none")]
3265 pub api_version: Option<String>,
3266 #[serde(skip_serializing_if = "Option::is_none")]
3267 pub kind: Option<String>,
3268 pub metadata: ObjectMeta,
3269 #[serde(skip_serializing_if = "Option::is_none")]
3270 pub spec: Option<VolumeSnapshotSpec>,
3271 #[serde(skip_serializing_if = "Option::is_none")]
3272 pub status: Option<VolumeSnapshotStatus>,
3273}
3274
3275#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3276pub struct VolumeSnapshotList {
3277 #[serde(skip_serializing_if = "Option::is_none")]
3278 pub api_version: Option<String>,
3279 #[serde(skip_serializing_if = "Option::is_none")]
3280 pub kind: Option<String>,
3281 #[serde(default)]
3282 pub metadata: ListMeta,
3283 pub items: Vec<VolumeSnapshot>,
3284}
3285
3286#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3287pub struct Volume {
3288 #[serde(skip_serializing_if = "Option::is_none")]
3289 pub name: Option<String>,
3290 #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
3291 pub volume_type: Option<String>,
3292 #[serde(skip_serializing_if = "Option::is_none")]
3293 pub source: Option<String>,
3294}
3295
3296#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3297pub struct VirtualMachineDomain {
3298 #[serde(skip_serializing_if = "Option::is_none")]
3299 pub cpu: Option<String>,
3300 #[serde(skip_serializing_if = "Option::is_none")]
3301 pub memory: Option<String>,
3302 #[serde(skip_serializing_if = "Option::is_none")]
3303 pub devices: Option<HashMap<String, Value>>,
3304}
3305
3306#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3307pub struct VirtualMachineInstanceSpec {
3308 #[serde(skip_serializing_if = "Option::is_none")]
3309 pub domain: Option<VirtualMachineDomain>,
3310 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
3311 pub node_selector: HashMap<String, String>,
3312 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3313 pub networks: Vec<String>,
3314 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3315 pub volumes: Vec<Volume>,
3316}
3317
3318#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3319pub struct VirtualMachineTemplateSpec {
3320 #[serde(skip_serializing_if = "Option::is_none")]
3321 pub metadata: Option<ObjectMeta>,
3322 #[serde(skip_serializing_if = "Option::is_none")]
3323 pub spec: Option<VirtualMachineInstanceSpec>,
3324}
3325
3326#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3327pub struct VirtualMachineSpec {
3328 #[serde(skip_serializing_if = "Option::is_none")]
3329 pub run_strategy: Option<String>,
3330 #[serde(skip_serializing_if = "Option::is_none")]
3331 pub template: Option<VirtualMachineTemplateSpec>,
3332 #[serde(skip_serializing_if = "Option::is_none")]
3333 pub cpu: Option<String>,
3334 #[serde(skip_serializing_if = "Option::is_none")]
3335 pub memory: Option<String>,
3336 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3337 pub disks: Vec<Volume>,
3338 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3339 pub networks: Vec<String>,
3340}
3341
3342#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3343pub struct VirtualMachine {
3344 #[serde(skip_serializing_if = "Option::is_none")]
3345 pub api_version: Option<String>,
3346 #[serde(skip_serializing_if = "Option::is_none")]
3347 pub kind: Option<String>,
3348 pub metadata: ObjectMeta,
3349 #[serde(skip_serializing_if = "Option::is_none")]
3350 pub spec: Option<VirtualMachineSpec>,
3351 #[serde(skip_serializing_if = "Option::is_none")]
3352 pub status: Option<HashMap<String, Value>>,
3353}
3354
3355#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3356pub struct VirtualMachineList {
3357 #[serde(skip_serializing_if = "Option::is_none")]
3358 pub api_version: Option<String>,
3359 #[serde(skip_serializing_if = "Option::is_none")]
3360 pub kind: Option<String>,
3361 #[serde(default)]
3362 pub metadata: ListMeta,
3363 pub items: Vec<VirtualMachine>,
3364}
3365
3366#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3367pub struct VirtualMachineInstance {
3368 #[serde(skip_serializing_if = "Option::is_none")]
3369 pub api_version: Option<String>,
3370 #[serde(skip_serializing_if = "Option::is_none")]
3371 pub kind: Option<String>,
3372 pub metadata: ObjectMeta,
3373 #[serde(skip_serializing_if = "Option::is_none")]
3374 pub spec: Option<VirtualMachineInstanceSpec>,
3375 #[serde(skip_serializing_if = "Option::is_none")]
3376 pub status: Option<HashMap<String, Value>>,
3377}
3378
3379#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3380pub struct VirtualMachineInstanceList {
3381 #[serde(skip_serializing_if = "Option::is_none")]
3382 pub api_version: Option<String>,
3383 #[serde(skip_serializing_if = "Option::is_none")]
3384 pub kind: Option<String>,
3385 #[serde(default)]
3386 pub metadata: ListMeta,
3387 pub items: Vec<VirtualMachineInstance>,
3388}
3389
3390#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3391pub struct VmSnapshotSpec {
3392 #[serde(skip_serializing_if = "Option::is_none")]
3393 pub source_name: Option<String>,
3394}
3395
3396#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3397pub struct VmSnapshot {
3398 #[serde(skip_serializing_if = "Option::is_none")]
3399 pub api_version: Option<String>,
3400 #[serde(skip_serializing_if = "Option::is_none")]
3401 pub kind: Option<String>,
3402 pub metadata: ObjectMeta,
3403 #[serde(skip_serializing_if = "Option::is_none")]
3404 pub spec: Option<VmSnapshotSpec>,
3405 #[serde(skip_serializing_if = "Option::is_none")]
3406 pub status: Option<HashMap<String, Value>>,
3407}
3408
3409#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3410pub struct VmSnapshotList {
3411 #[serde(skip_serializing_if = "Option::is_none")]
3412 pub api_version: Option<String>,
3413 #[serde(skip_serializing_if = "Option::is_none")]
3414 pub kind: Option<String>,
3415 #[serde(default)]
3416 pub metadata: ListMeta,
3417 pub items: Vec<VmSnapshot>,
3418}
3419
3420#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3421pub struct VmMemoryDumpSpec {
3422 #[serde(skip_serializing_if = "Option::is_none")]
3423 pub source_name: Option<String>,
3424 pub file: CreateFileRequest,
3425}
3426
3427#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3428pub struct VmMemoryDumpStatus {
3429 #[serde(skip_serializing_if = "Option::is_none")]
3430 pub ready: Option<bool>,
3431 #[serde(skip_serializing_if = "Option::is_none")]
3432 pub file_id: Option<Uuid>,
3433 #[serde(skip_serializing_if = "Option::is_none")]
3434 pub file_name: Option<String>,
3435 #[serde(skip_serializing_if = "Option::is_none")]
3436 pub size_bytes: Option<i64>,
3437 #[serde(skip_serializing_if = "Option::is_none")]
3438 pub content_type: Option<String>,
3439 #[serde(skip_serializing_if = "Option::is_none")]
3440 pub created_at: Option<DateTime<Utc>>,
3441 #[serde(skip_serializing_if = "Option::is_none")]
3442 pub message: Option<String>,
3443}
3444
3445#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3446pub struct VmMemoryDump {
3447 #[serde(skip_serializing_if = "Option::is_none")]
3448 pub api_version: Option<String>,
3449 #[serde(skip_serializing_if = "Option::is_none")]
3450 pub kind: Option<String>,
3451 pub metadata: ObjectMeta,
3452 #[serde(skip_serializing_if = "Option::is_none")]
3453 pub spec: Option<VmMemoryDumpSpec>,
3454 #[serde(skip_serializing_if = "Option::is_none")]
3455 pub status: Option<VmMemoryDumpStatus>,
3456}
3457
3458#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3459pub struct VmMemoryDumpList {
3460 #[serde(skip_serializing_if = "Option::is_none")]
3461 pub api_version: Option<String>,
3462 #[serde(skip_serializing_if = "Option::is_none")]
3463 pub kind: Option<String>,
3464 #[serde(default)]
3465 pub metadata: ListMeta,
3466 pub items: Vec<VmMemoryDump>,
3467}
3468
3469#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3470pub struct NetworkCaptureTarget {
3471 pub kind: String,
3472 #[serde(skip_serializing_if = "Option::is_none")]
3473 pub name: Option<String>,
3474 #[serde(skip_serializing_if = "Option::is_none")]
3475 pub namespace: Option<String>,
3476 #[serde(skip_serializing_if = "Option::is_none")]
3477 pub container_id: Option<String>,
3478 #[serde(skip_serializing_if = "Option::is_none")]
3479 pub pod_name: Option<String>,
3480 #[serde(skip_serializing_if = "Option::is_none")]
3481 pub container_name: Option<String>,
3482}
3483
3484#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3485pub struct NetworkCaptureFilter {
3486 #[serde(skip_serializing_if = "Option::is_none")]
3487 pub bpf: Option<String>,
3488 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3489 pub protocols: Vec<String>,
3490 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3491 pub ports: Vec<u16>,
3492 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3493 pub cidrs: Vec<String>,
3494}
3495
3496#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3497pub struct NetworkCaptureRotation {
3498 #[serde(skip_serializing_if = "Option::is_none")]
3499 pub enabled: Option<bool>,
3500 #[serde(skip_serializing_if = "Option::is_none")]
3501 pub max_bytes: Option<i64>,
3502 #[serde(skip_serializing_if = "Option::is_none")]
3503 pub max_duration_seconds: Option<u64>,
3504 #[serde(skip_serializing_if = "Option::is_none")]
3505 pub max_files: Option<u32>,
3506}
3507
3508#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3509pub struct NetworkCaptureCaptureOptions {
3510 #[serde(skip_serializing_if = "Option::is_none")]
3511 pub format: Option<String>,
3512 #[serde(skip_serializing_if = "Option::is_none")]
3513 pub snaplen: Option<u32>,
3514 #[serde(skip_serializing_if = "Option::is_none")]
3515 pub max_packets: Option<u64>,
3516 #[serde(skip_serializing_if = "Option::is_none")]
3517 pub max_bytes: Option<i64>,
3518 #[serde(skip_serializing_if = "Option::is_none")]
3519 pub rotation: Option<NetworkCaptureRotation>,
3520 #[serde(skip_serializing_if = "Option::is_none")]
3521 pub compression: Option<String>,
3522}
3523
3524#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3525pub struct NetworkCaptureLifecycle {
3526 #[serde(skip_serializing_if = "Option::is_none")]
3527 pub desired_state: Option<String>,
3528 #[serde(skip_serializing_if = "Option::is_none")]
3529 pub stop_at: Option<DateTime<Utc>>,
3530 #[serde(skip_serializing_if = "Option::is_none")]
3531 pub ttl_seconds_after_finished: Option<u64>,
3532}
3533
3534#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3535pub struct NetworkCaptureSegment {
3536 #[serde(skip_serializing_if = "Option::is_none")]
3537 pub index: Option<u32>,
3538 #[serde(skip_serializing_if = "Option::is_none")]
3539 pub file_id: Option<Uuid>,
3540 #[serde(skip_serializing_if = "Option::is_none")]
3541 pub size_bytes: Option<i64>,
3542 #[serde(skip_serializing_if = "Option::is_none")]
3543 pub started_at: Option<DateTime<Utc>>,
3544 #[serde(skip_serializing_if = "Option::is_none")]
3545 pub finished_at: Option<DateTime<Utc>>,
3546}
3547
3548#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3549pub struct NetworkCaptureSpec {
3550 pub target: NetworkCaptureTarget,
3551 #[serde(skip_serializing_if = "Option::is_none")]
3552 pub direction: Option<String>,
3553 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3554 pub interfaces: Vec<String>,
3555 #[serde(skip_serializing_if = "Option::is_none")]
3556 pub filter: Option<NetworkCaptureFilter>,
3557 #[serde(skip_serializing_if = "Option::is_none")]
3558 pub capture: Option<NetworkCaptureCaptureOptions>,
3559 pub file: CaptureFileRequest,
3560 #[serde(skip_serializing_if = "Option::is_none")]
3561 pub run_id: Option<Uuid>,
3562 #[serde(skip_serializing_if = "Option::is_none")]
3563 pub lifecycle: Option<NetworkCaptureLifecycle>,
3564}
3565
3566#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3567pub struct NetworkCaptureStatus {
3568 #[serde(skip_serializing_if = "Option::is_none")]
3569 pub phase: Option<String>,
3570 #[serde(skip_serializing_if = "Option::is_none")]
3571 pub message: Option<String>,
3572 #[serde(skip_serializing_if = "Option::is_none")]
3573 pub started_at: Option<DateTime<Utc>>,
3574 #[serde(skip_serializing_if = "Option::is_none")]
3575 pub finished_at: Option<DateTime<Utc>>,
3576 #[serde(skip_serializing_if = "Option::is_none")]
3577 pub bytes_captured: Option<i64>,
3578 #[serde(skip_serializing_if = "Option::is_none")]
3579 pub packets_captured: Option<i64>,
3580 #[serde(skip_serializing_if = "Option::is_none")]
3581 pub file_id: Option<Uuid>,
3582 #[serde(skip_serializing_if = "Option::is_none")]
3583 pub file_name: Option<String>,
3584 #[serde(skip_serializing_if = "Option::is_none")]
3585 pub content_type: Option<String>,
3586 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3587 pub segments: Vec<NetworkCaptureSegment>,
3588}
3589
3590#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3591pub struct NetworkCapture {
3592 #[serde(skip_serializing_if = "Option::is_none")]
3593 pub api_version: Option<String>,
3594 #[serde(skip_serializing_if = "Option::is_none")]
3595 pub kind: Option<String>,
3596 pub metadata: ObjectMeta,
3597 #[serde(skip_serializing_if = "Option::is_none")]
3598 pub spec: Option<NetworkCaptureSpec>,
3599 #[serde(skip_serializing_if = "Option::is_none")]
3600 pub status: Option<NetworkCaptureStatus>,
3601}
3602
3603#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3604pub struct NetworkCaptureList {
3605 #[serde(skip_serializing_if = "Option::is_none")]
3606 pub api_version: Option<String>,
3607 #[serde(skip_serializing_if = "Option::is_none")]
3608 pub kind: Option<String>,
3609 #[serde(default)]
3610 pub metadata: ListMeta,
3611 pub items: Vec<NetworkCapture>,
3612}
3613
3614#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3615pub struct VmMigrationSpec {
3616 #[serde(skip_serializing_if = "Option::is_none")]
3617 pub vmi_name: Option<String>,
3618 #[serde(skip_serializing_if = "Option::is_none")]
3619 pub target_node: Option<String>,
3620}
3621
3622#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3623pub struct VmMigration {
3624 #[serde(skip_serializing_if = "Option::is_none")]
3625 pub api_version: Option<String>,
3626 #[serde(skip_serializing_if = "Option::is_none")]
3627 pub kind: Option<String>,
3628 pub metadata: ObjectMeta,
3629 #[serde(skip_serializing_if = "Option::is_none")]
3630 pub spec: Option<VmMigrationSpec>,
3631 #[serde(skip_serializing_if = "Option::is_none")]
3632 pub status: Option<HashMap<String, Value>>,
3633}
3634
3635#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3636pub struct VmMigrationList {
3637 #[serde(skip_serializing_if = "Option::is_none")]
3638 pub api_version: Option<String>,
3639 #[serde(skip_serializing_if = "Option::is_none")]
3640 pub kind: Option<String>,
3641 #[serde(default)]
3642 pub metadata: ListMeta,
3643 pub items: Vec<VmMigration>,
3644}
3645
3646#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3647pub struct ConsoleSession {
3648 pub protocol: String,
3649 pub url: String,
3650}
3651
3652#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3653pub struct ContainerPort {
3654 #[serde(skip_serializing_if = "Option::is_none")]
3655 pub name: Option<String>,
3656 pub container_port: u16,
3657 #[serde(skip_serializing_if = "Option::is_none")]
3658 pub protocol: Option<String>,
3659}
3660
3661#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3662pub struct EnvVar {
3663 pub name: String,
3664 #[serde(skip_serializing_if = "Option::is_none")]
3665 pub value: Option<String>,
3666}
3667
3668#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, Default)]
3669pub struct ResourceRequirements {
3670 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
3671 pub limits: HashMap<String, String>,
3672 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
3673 pub requests: HashMap<String, String>,
3674}
3675
3676#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3677pub struct Toleration {
3678 #[serde(skip_serializing_if = "Option::is_none")]
3679 pub key: Option<String>,
3680 #[serde(skip_serializing_if = "Option::is_none")]
3681 pub operator: Option<String>,
3682 #[serde(skip_serializing_if = "Option::is_none")]
3683 pub value: Option<String>,
3684 #[serde(skip_serializing_if = "Option::is_none")]
3685 pub effect: Option<String>,
3686 #[serde(skip_serializing_if = "Option::is_none")]
3687 pub toleration_seconds: Option<i64>,
3688}
3689
3690#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3691pub struct PreferredSchedulingTerm {
3692 pub weight: i32,
3693 pub preference: LabelSelector,
3694}
3695
3696#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3697pub struct NodeAffinity {
3698 #[serde(skip_serializing_if = "Option::is_none")]
3699 pub required: Option<LabelSelector>,
3700 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3701 pub preferred: Vec<PreferredSchedulingTerm>,
3702}
3703
3704#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3705pub struct PodAffinityTerm {
3706 pub label_selector: LabelSelector,
3707 pub topology_key: String,
3708}
3709
3710#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3711pub struct WeightedPodAffinityTerm {
3712 pub weight: i32,
3713 pub pod_affinity_term: PodAffinityTerm,
3714}
3715
3716#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3717pub struct PodAffinity {
3718 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3719 pub required: Vec<PodAffinityTerm>,
3720 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3721 pub preferred: Vec<WeightedPodAffinityTerm>,
3722}
3723
3724#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3725pub struct Affinity {
3726 #[serde(skip_serializing_if = "Option::is_none")]
3727 pub node_affinity: Option<NodeAffinity>,
3728 #[serde(skip_serializing_if = "Option::is_none")]
3729 pub pod_affinity: Option<PodAffinity>,
3730 #[serde(skip_serializing_if = "Option::is_none")]
3731 pub pod_anti_affinity: Option<PodAffinity>,
3732}
3733
3734#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3735pub struct PodContainer {
3736 pub name: String,
3737 #[serde(skip_serializing_if = "Option::is_none")]
3738 pub image: Option<String>,
3739 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3740 pub command: Vec<String>,
3741 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3742 pub args: Vec<String>,
3743 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3744 pub env: Vec<EnvVar>,
3745 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3746 pub ports: Vec<ContainerPort>,
3747 #[serde(default, skip_serializing_if = "Option::is_none")]
3748 pub resources: Option<ResourceRequirements>,
3749}
3750
3751#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3752pub struct PodSpec {
3753 #[serde(skip_serializing_if = "Option::is_none")]
3754 pub service_account_name: Option<String>,
3755 #[serde(skip_serializing_if = "Option::is_none")]
3756 pub node_name: Option<String>,
3757 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
3758 pub node_selector: HashMap<String, String>,
3759 #[serde(skip_serializing_if = "Option::is_none")]
3760 pub priority_class_name: Option<String>,
3761 #[serde(skip_serializing_if = "Option::is_none")]
3762 pub priority: Option<i32>,
3763 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3764 pub tolerations: Vec<Toleration>,
3765 #[serde(skip_serializing_if = "Option::is_none")]
3766 pub affinity: Option<Affinity>,
3767 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3768 pub containers: Vec<PodContainer>,
3769 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3770 pub volumes: Vec<Value>,
3771}
3772
3773#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3774pub struct PodContainerStatus {
3775 pub name: String,
3776 #[serde(skip_serializing_if = "Option::is_none")]
3777 pub container_id: Option<String>,
3778 #[serde(skip_serializing_if = "Option::is_none")]
3779 pub ready: Option<bool>,
3780 #[serde(skip_serializing_if = "Option::is_none")]
3781 pub restart_count: Option<i32>,
3782}
3783
3784#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3785pub struct PodStatus {
3786 #[serde(skip_serializing_if = "Option::is_none")]
3787 pub phase: Option<String>,
3788 #[serde(skip_serializing_if = "Option::is_none")]
3789 pub pod_ip: Option<String>,
3790 #[serde(skip_serializing_if = "Option::is_none")]
3791 pub host_ip: Option<String>,
3792 #[serde(skip_serializing_if = "Option::is_none")]
3793 pub qos_class: Option<String>,
3794 #[serde(skip_serializing_if = "Option::is_none")]
3795 pub start_time: Option<DateTime<Utc>>,
3796 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3797 pub container_statuses: Vec<PodContainerStatus>,
3798 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3799 pub conditions: Vec<PodCondition>,
3800}
3801
3802#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3803pub struct PodCondition {
3804 #[serde(rename = "type")]
3805 pub condition_type: String,
3806 pub status: String,
3807 #[serde(skip_serializing_if = "Option::is_none")]
3808 pub reason: Option<String>,
3809 #[serde(skip_serializing_if = "Option::is_none")]
3810 pub message: Option<String>,
3811 #[serde(skip_serializing_if = "Option::is_none")]
3812 pub last_probe_time: Option<DateTime<Utc>>,
3813 #[serde(skip_serializing_if = "Option::is_none")]
3814 pub last_transition_time: Option<DateTime<Utc>>,
3815}
3816
3817#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3818pub struct PodTemplateSpec {
3819 pub metadata: ObjectMeta,
3820 pub spec: PodSpec,
3821}
3822
3823#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3824pub struct Pod {
3825 #[serde(skip_serializing_if = "Option::is_none")]
3826 pub api_version: Option<String>,
3827 #[serde(skip_serializing_if = "Option::is_none")]
3828 pub kind: Option<String>,
3829 pub metadata: ObjectMeta,
3830 pub spec: PodSpec,
3831 #[serde(skip_serializing_if = "Option::is_none")]
3832 pub status: Option<PodStatus>,
3833}
3834
3835#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3836pub struct PodStatusUpdate {
3837 #[serde(skip_serializing_if = "Option::is_none")]
3838 pub api_version: Option<String>,
3839 #[serde(skip_serializing_if = "Option::is_none")]
3840 pub kind: Option<String>,
3841 pub metadata: ObjectMeta,
3842 #[serde(skip_serializing_if = "Option::is_none")]
3843 pub status: Option<PodStatus>,
3844}
3845
3846#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3847pub struct PodList {
3848 #[serde(skip_serializing_if = "Option::is_none")]
3849 pub api_version: Option<String>,
3850 #[serde(skip_serializing_if = "Option::is_none")]
3851 pub kind: Option<String>,
3852 #[serde(default)]
3853 pub metadata: ListMeta,
3854 pub items: Vec<Pod>,
3855}
3856
3857#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3858pub struct DeploymentSpec {
3859 #[serde(skip_serializing_if = "Option::is_none")]
3860 pub replicas: Option<i32>,
3861 pub selector: LabelSelector,
3862 pub template: PodTemplateSpec,
3863 #[serde(skip_serializing_if = "Option::is_none")]
3864 pub strategy: Option<HashMap<String, Value>>,
3865}
3866
3867#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3868pub struct WorkloadDeploymentStatus {
3869 #[serde(skip_serializing_if = "Option::is_none")]
3870 pub available_replicas: Option<i32>,
3871 #[serde(skip_serializing_if = "Option::is_none")]
3872 pub updated_replicas: Option<i32>,
3873}
3874
3875#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3876pub struct Deployment {
3877 #[serde(skip_serializing_if = "Option::is_none")]
3878 pub api_version: Option<String>,
3879 #[serde(skip_serializing_if = "Option::is_none")]
3880 pub kind: Option<String>,
3881 pub metadata: ObjectMeta,
3882 #[serde(skip_serializing_if = "Option::is_none")]
3883 pub spec: Option<DeploymentSpec>,
3884 #[serde(skip_serializing_if = "Option::is_none")]
3885 pub status: Option<WorkloadDeploymentStatus>,
3886}
3887
3888#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3889pub struct DeploymentList {
3890 #[serde(skip_serializing_if = "Option::is_none")]
3891 pub api_version: Option<String>,
3892 #[serde(skip_serializing_if = "Option::is_none")]
3893 pub kind: Option<String>,
3894 #[serde(default)]
3895 pub metadata: ListMeta,
3896 pub items: Vec<Deployment>,
3897}
3898
3899#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3900pub struct ReplicaSet {
3901 #[serde(skip_serializing_if = "Option::is_none")]
3902 pub api_version: Option<String>,
3903 #[serde(skip_serializing_if = "Option::is_none")]
3904 pub kind: Option<String>,
3905 pub metadata: ObjectMeta,
3906 #[serde(skip_serializing_if = "Option::is_none")]
3907 pub spec: Option<DeploymentSpec>,
3908 #[serde(skip_serializing_if = "Option::is_none")]
3909 pub status: Option<HashMap<String, Value>>,
3910}
3911
3912#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3913pub struct ReplicaSetList {
3914 #[serde(skip_serializing_if = "Option::is_none")]
3915 pub api_version: Option<String>,
3916 #[serde(skip_serializing_if = "Option::is_none")]
3917 pub kind: Option<String>,
3918 #[serde(default)]
3919 pub metadata: ListMeta,
3920 pub items: Vec<ReplicaSet>,
3921}
3922
3923#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3924pub struct StatefulSetSpec {
3925 #[serde(skip_serializing_if = "Option::is_none")]
3926 pub replicas: Option<i32>,
3927 #[serde(skip_serializing_if = "Option::is_none")]
3928 pub service_name: Option<String>,
3929 pub selector: LabelSelector,
3930 pub template: PodTemplateSpec,
3931 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3932 pub volume_claim_templates: Vec<Value>,
3933}
3934
3935#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3936pub struct StatefulSet {
3937 #[serde(skip_serializing_if = "Option::is_none")]
3938 pub api_version: Option<String>,
3939 #[serde(skip_serializing_if = "Option::is_none")]
3940 pub kind: Option<String>,
3941 pub metadata: ObjectMeta,
3942 #[serde(skip_serializing_if = "Option::is_none")]
3943 pub spec: Option<StatefulSetSpec>,
3944 #[serde(skip_serializing_if = "Option::is_none")]
3945 pub status: Option<HashMap<String, Value>>,
3946}
3947
3948#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3949pub struct StatefulSetList {
3950 #[serde(skip_serializing_if = "Option::is_none")]
3951 pub api_version: Option<String>,
3952 #[serde(skip_serializing_if = "Option::is_none")]
3953 pub kind: Option<String>,
3954 #[serde(default)]
3955 pub metadata: ListMeta,
3956 pub items: Vec<StatefulSet>,
3957}
3958
3959#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3960pub struct DaemonSetSpec {
3961 pub selector: LabelSelector,
3962 pub template: PodTemplateSpec,
3963 #[serde(skip_serializing_if = "Option::is_none")]
3964 pub update_strategy: Option<HashMap<String, Value>>,
3965}
3966
3967#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3968pub struct DaemonSet {
3969 #[serde(skip_serializing_if = "Option::is_none")]
3970 pub api_version: Option<String>,
3971 #[serde(skip_serializing_if = "Option::is_none")]
3972 pub kind: Option<String>,
3973 pub metadata: ObjectMeta,
3974 #[serde(skip_serializing_if = "Option::is_none")]
3975 pub spec: Option<DaemonSetSpec>,
3976 #[serde(skip_serializing_if = "Option::is_none")]
3977 pub status: Option<HashMap<String, Value>>,
3978}
3979
3980#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3981pub struct DaemonSetList {
3982 #[serde(skip_serializing_if = "Option::is_none")]
3983 pub api_version: Option<String>,
3984 #[serde(skip_serializing_if = "Option::is_none")]
3985 pub kind: Option<String>,
3986 #[serde(default)]
3987 pub metadata: ListMeta,
3988 pub items: Vec<DaemonSet>,
3989}
3990
3991#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
3992pub struct JobSpec {
3993 #[serde(skip_serializing_if = "Option::is_none")]
3994 pub parallelism: Option<i32>,
3995 #[serde(skip_serializing_if = "Option::is_none")]
3996 pub completions: Option<i32>,
3997 #[serde(skip_serializing_if = "Option::is_none")]
3998 pub backoff_limit: Option<i32>,
3999 pub template: PodTemplateSpec,
4000}
4001
4002#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4003pub struct Job {
4004 #[serde(skip_serializing_if = "Option::is_none")]
4005 pub api_version: Option<String>,
4006 #[serde(skip_serializing_if = "Option::is_none")]
4007 pub kind: Option<String>,
4008 pub metadata: ObjectMeta,
4009 #[serde(skip_serializing_if = "Option::is_none")]
4010 pub spec: Option<JobSpec>,
4011 #[serde(skip_serializing_if = "Option::is_none")]
4012 pub status: Option<HashMap<String, Value>>,
4013}
4014
4015#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4016pub struct JobList {
4017 #[serde(skip_serializing_if = "Option::is_none")]
4018 pub api_version: Option<String>,
4019 #[serde(skip_serializing_if = "Option::is_none")]
4020 pub kind: Option<String>,
4021 #[serde(default)]
4022 pub metadata: ListMeta,
4023 pub items: Vec<Job>,
4024}
4025
4026#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4027pub struct JobTemplateSpec {
4028 pub spec: JobSpec,
4029}
4030
4031#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4032pub struct CronJobSpec {
4033 pub schedule: String,
4034 pub job_template: JobTemplateSpec,
4035}
4036
4037#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4038pub struct CronJob {
4039 #[serde(skip_serializing_if = "Option::is_none")]
4040 pub api_version: Option<String>,
4041 #[serde(skip_serializing_if = "Option::is_none")]
4042 pub kind: Option<String>,
4043 pub metadata: ObjectMeta,
4044 #[serde(skip_serializing_if = "Option::is_none")]
4045 pub spec: Option<CronJobSpec>,
4046 #[serde(skip_serializing_if = "Option::is_none")]
4047 pub status: Option<HashMap<String, Value>>,
4048}
4049
4050#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4051pub struct CronJobList {
4052 #[serde(skip_serializing_if = "Option::is_none")]
4053 pub api_version: Option<String>,
4054 #[serde(skip_serializing_if = "Option::is_none")]
4055 pub kind: Option<String>,
4056 #[serde(default)]
4057 pub metadata: ListMeta,
4058 pub items: Vec<CronJob>,
4059}
4060
4061#[derive(Debug, Clone, Serialize, Deserialize, Default, ToSchema)]
4062pub struct ScaleSpec {
4063 #[serde(skip_serializing_if = "Option::is_none")]
4064 pub replicas: Option<i32>,
4065}
4066
4067#[derive(Debug, Clone, Serialize, Deserialize, Default, ToSchema)]
4068pub struct ScaleStatus {
4069 #[serde(skip_serializing_if = "Option::is_none")]
4070 pub replicas: Option<i32>,
4071}
4072
4073#[derive(Debug, Clone, Serialize, Deserialize, Default, ToSchema)]
4074pub struct Scale {
4075 #[serde(skip_serializing_if = "Option::is_none")]
4076 pub spec: Option<ScaleSpec>,
4077 #[serde(skip_serializing_if = "Option::is_none")]
4078 pub status: Option<ScaleStatus>,
4079}
4080
4081#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4082pub struct CrossVersionObjectReference {
4083 #[serde(skip_serializing_if = "Option::is_none")]
4084 pub api_version: Option<String>,
4085 #[serde(skip_serializing_if = "Option::is_none")]
4086 pub kind: Option<String>,
4087 pub name: String,
4088}
4089
4090#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4091pub struct MetricIdentifier {
4092 pub name: String,
4093 #[serde(skip_serializing_if = "Option::is_none")]
4094 pub selector: Option<LabelSelector>,
4095}
4096
4097#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4098pub struct MetricTarget {
4099 #[serde(rename = "type")]
4100 pub target_type: String,
4101 #[serde(skip_serializing_if = "Option::is_none")]
4102 pub value: Option<String>,
4103 #[serde(skip_serializing_if = "Option::is_none")]
4104 pub average_value: Option<String>,
4105 #[serde(skip_serializing_if = "Option::is_none")]
4106 pub average_utilization: Option<i32>,
4107}
4108
4109#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4110pub struct MetricValueStatus {
4111 #[serde(skip_serializing_if = "Option::is_none")]
4112 pub value: Option<String>,
4113 #[serde(skip_serializing_if = "Option::is_none")]
4114 pub average_value: Option<String>,
4115 #[serde(skip_serializing_if = "Option::is_none")]
4116 pub average_utilization: Option<i32>,
4117}
4118
4119#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4120pub struct ResourceMetricSource {
4121 pub name: String,
4122 pub target: MetricTarget,
4123}
4124
4125#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4126pub struct ResourceMetricStatus {
4127 pub name: String,
4128 pub current: MetricValueStatus,
4129}
4130
4131#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4132pub struct PodsMetricSource {
4133 pub metric: MetricIdentifier,
4134 pub target: MetricTarget,
4135}
4136
4137#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4138pub struct PodsMetricStatus {
4139 pub metric: MetricIdentifier,
4140 pub current: MetricValueStatus,
4141}
4142
4143#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4144pub struct ObjectMetricSource {
4145 pub described_object: CrossVersionObjectReference,
4146 pub metric: MetricIdentifier,
4147 pub target: MetricTarget,
4148}
4149
4150#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4151pub struct ObjectMetricStatus {
4152 pub described_object: CrossVersionObjectReference,
4153 pub metric: MetricIdentifier,
4154 pub current: MetricValueStatus,
4155}
4156
4157#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4158pub struct ExternalMetricSource {
4159 pub metric: MetricIdentifier,
4160 pub target: MetricTarget,
4161}
4162
4163#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4164pub struct ExternalMetricStatus {
4165 pub metric: MetricIdentifier,
4166 pub current: MetricValueStatus,
4167}
4168
4169#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4170pub struct MetricSpec {
4171 #[serde(rename = "type")]
4172 pub metric_type: String,
4173 #[serde(skip_serializing_if = "Option::is_none")]
4174 pub resource: Option<ResourceMetricSource>,
4175 #[serde(skip_serializing_if = "Option::is_none")]
4176 pub pods: Option<PodsMetricSource>,
4177 #[serde(skip_serializing_if = "Option::is_none")]
4178 pub object: Option<ObjectMetricSource>,
4179 #[serde(skip_serializing_if = "Option::is_none")]
4180 pub external: Option<ExternalMetricSource>,
4181}
4182
4183#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4184pub struct MetricStatus {
4185 #[serde(rename = "type")]
4186 pub metric_type: String,
4187 #[serde(skip_serializing_if = "Option::is_none")]
4188 pub resource: Option<ResourceMetricStatus>,
4189 #[serde(skip_serializing_if = "Option::is_none")]
4190 pub pods: Option<PodsMetricStatus>,
4191 #[serde(skip_serializing_if = "Option::is_none")]
4192 pub object: Option<ObjectMetricStatus>,
4193 #[serde(skip_serializing_if = "Option::is_none")]
4194 pub external: Option<ExternalMetricStatus>,
4195}
4196
4197#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4198pub struct AutoscalerCondition {
4199 #[serde(rename = "type")]
4200 pub condition_type: String,
4201 pub status: String,
4202 #[serde(skip_serializing_if = "Option::is_none")]
4203 pub reason: Option<String>,
4204 #[serde(skip_serializing_if = "Option::is_none")]
4205 pub message: Option<String>,
4206 #[serde(skip_serializing_if = "Option::is_none")]
4207 pub last_transition_time: Option<DateTime<Utc>>,
4208}
4209
4210#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4211pub struct HorizontalPodAutoscalerBehavior {
4212 #[serde(skip_serializing_if = "Option::is_none")]
4213 pub scale_up: Option<HorizontalPodAutoscalerScalingRules>,
4214 #[serde(skip_serializing_if = "Option::is_none")]
4215 pub scale_down: Option<HorizontalPodAutoscalerScalingRules>,
4216}
4217
4218#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4219pub struct HorizontalPodAutoscalerScalingRules {
4220 #[serde(skip_serializing_if = "Option::is_none")]
4221 pub stabilization_window_seconds: Option<i32>,
4222 #[serde(skip_serializing_if = "Option::is_none")]
4223 pub select_policy: Option<String>,
4224 #[serde(default, skip_serializing_if = "Vec::is_empty")]
4225 pub policies: Vec<HorizontalPodAutoscalerScalingPolicy>,
4226}
4227
4228#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4229pub struct HorizontalPodAutoscalerScalingPolicy {
4230 #[serde(rename = "type")]
4231 pub policy_type: String,
4232 pub value: i32,
4233 pub period_seconds: i32,
4234}
4235
4236#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4237pub struct HorizontalPodAutoscalerSpec {
4238 pub scale_target_ref: CrossVersionObjectReference,
4239 #[serde(skip_serializing_if = "Option::is_none")]
4240 pub min_replicas: Option<i32>,
4241 pub max_replicas: i32,
4242 #[serde(default, skip_serializing_if = "Vec::is_empty")]
4243 pub metrics: Vec<MetricSpec>,
4244 #[serde(skip_serializing_if = "Option::is_none")]
4245 pub behavior: Option<HorizontalPodAutoscalerBehavior>,
4246}
4247
4248#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4249pub struct HorizontalPodAutoscalerStatus {
4250 #[serde(skip_serializing_if = "Option::is_none")]
4251 pub current_replicas: Option<i32>,
4252 #[serde(skip_serializing_if = "Option::is_none")]
4253 pub desired_replicas: Option<i32>,
4254 #[serde(skip_serializing_if = "Option::is_none")]
4255 pub last_scale_time: Option<DateTime<Utc>>,
4256 #[serde(default, skip_serializing_if = "Vec::is_empty")]
4257 pub current_metrics: Vec<MetricStatus>,
4258 #[serde(default, skip_serializing_if = "Vec::is_empty")]
4259 pub conditions: Vec<AutoscalerCondition>,
4260}
4261
4262#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4263pub struct HorizontalPodAutoscaler {
4264 #[serde(skip_serializing_if = "Option::is_none")]
4265 pub api_version: Option<String>,
4266 #[serde(skip_serializing_if = "Option::is_none")]
4267 pub kind: Option<String>,
4268 pub metadata: ObjectMeta,
4269 #[serde(skip_serializing_if = "Option::is_none")]
4270 pub spec: Option<HorizontalPodAutoscalerSpec>,
4271 #[serde(skip_serializing_if = "Option::is_none")]
4272 pub status: Option<HorizontalPodAutoscalerStatus>,
4273}
4274
4275#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4276pub struct HorizontalPodAutoscalerList {
4277 #[serde(skip_serializing_if = "Option::is_none")]
4278 pub api_version: Option<String>,
4279 #[serde(skip_serializing_if = "Option::is_none")]
4280 pub kind: Option<String>,
4281 #[serde(default)]
4282 pub metadata: ListMeta,
4283 pub items: Vec<HorizontalPodAutoscaler>,
4284}
4285
4286#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4287pub struct VerticalPodAutoscalerUpdatePolicy {
4288 #[serde(skip_serializing_if = "Option::is_none")]
4289 pub update_mode: Option<String>,
4290}
4291
4292#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4293pub struct VerticalPodAutoscalerContainerPolicy {
4294 pub container_name: String,
4295 #[serde(skip_serializing_if = "Option::is_none")]
4296 pub mode: Option<String>,
4297 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
4298 pub min_allowed: HashMap<String, String>,
4299 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
4300 pub max_allowed: HashMap<String, String>,
4301 #[serde(default, skip_serializing_if = "Vec::is_empty")]
4302 pub controlled_resources: Vec<String>,
4303 #[serde(skip_serializing_if = "Option::is_none")]
4304 pub controlled_values: Option<String>,
4305}
4306
4307#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4308pub struct VerticalPodAutoscalerResourcePolicy {
4309 #[serde(default, skip_serializing_if = "Vec::is_empty")]
4310 pub container_policies: Vec<VerticalPodAutoscalerContainerPolicy>,
4311}
4312
4313#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4314pub struct VerticalPodAutoscalerSpec {
4315 pub target_ref: CrossVersionObjectReference,
4316 #[serde(skip_serializing_if = "Option::is_none")]
4317 pub update_policy: Option<VerticalPodAutoscalerUpdatePolicy>,
4318 #[serde(skip_serializing_if = "Option::is_none")]
4319 pub resource_policy: Option<VerticalPodAutoscalerResourcePolicy>,
4320}
4321
4322#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4323pub struct VerticalPodAutoscalerContainerRecommendation {
4324 pub container_name: String,
4325 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
4326 pub lower_bound: HashMap<String, String>,
4327 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
4328 pub target: HashMap<String, String>,
4329 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
4330 pub upper_bound: HashMap<String, String>,
4331 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
4332 pub uncapped_target: HashMap<String, String>,
4333}
4334
4335#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4336pub struct VerticalPodAutoscalerRecommendation {
4337 #[serde(default, skip_serializing_if = "Vec::is_empty")]
4338 pub container_recommendations: Vec<VerticalPodAutoscalerContainerRecommendation>,
4339}
4340
4341#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4342pub struct VerticalPodAutoscalerStatus {
4343 #[serde(skip_serializing_if = "Option::is_none")]
4344 pub recommendation: Option<VerticalPodAutoscalerRecommendation>,
4345 #[serde(default, skip_serializing_if = "Vec::is_empty")]
4346 pub conditions: Vec<AutoscalerCondition>,
4347}
4348
4349#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4350pub struct VerticalPodAutoscaler {
4351 #[serde(skip_serializing_if = "Option::is_none")]
4352 pub api_version: Option<String>,
4353 #[serde(skip_serializing_if = "Option::is_none")]
4354 pub kind: Option<String>,
4355 pub metadata: ObjectMeta,
4356 #[serde(skip_serializing_if = "Option::is_none")]
4357 pub spec: Option<VerticalPodAutoscalerSpec>,
4358 #[serde(skip_serializing_if = "Option::is_none")]
4359 pub status: Option<VerticalPodAutoscalerStatus>,
4360}
4361
4362#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4363pub struct VerticalPodAutoscalerList {
4364 #[serde(skip_serializing_if = "Option::is_none")]
4365 pub api_version: Option<String>,
4366 #[serde(skip_serializing_if = "Option::is_none")]
4367 pub kind: Option<String>,
4368 #[serde(default)]
4369 pub metadata: ListMeta,
4370 pub items: Vec<VerticalPodAutoscaler>,
4371}
4372
4373#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4374pub struct RolloutRequest {
4375 pub action: String,
4376}
4377
4378#[derive(Debug, Clone, Serialize, Deserialize, Default, ToSchema)]
4379pub struct MetricsSample {
4380 #[serde(flatten)]
4381 pub values: HashMap<String, Value>,
4382}
4383
4384#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4385pub struct MetricsSeries {
4386 pub ts: DateTime<Utc>,
4387 pub samples: Vec<MetricsSample>,
4388}
4389
4390#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4391pub struct Event {
4392 #[serde(skip_serializing_if = "Option::is_none")]
4393 pub api_version: Option<String>,
4394 #[serde(skip_serializing_if = "Option::is_none")]
4395 pub kind: Option<String>,
4396 pub metadata: ObjectMeta,
4397 #[serde(skip_serializing_if = "Option::is_none")]
4398 pub involved_object: Option<ObjectReference>,
4399 #[serde(skip_serializing_if = "Option::is_none")]
4400 pub reason: Option<String>,
4401 #[serde(skip_serializing_if = "Option::is_none")]
4402 pub message: Option<String>,
4403 #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
4404 pub event_type: Option<String>,
4405 #[serde(skip_serializing_if = "Option::is_none")]
4406 pub count: Option<i32>,
4407 #[serde(skip_serializing_if = "Option::is_none")]
4408 pub first_timestamp: Option<DateTime<Utc>>,
4409 #[serde(skip_serializing_if = "Option::is_none")]
4410 pub last_timestamp: Option<DateTime<Utc>>,
4411}
4412
4413#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4414pub struct EventList {
4415 #[serde(skip_serializing_if = "Option::is_none")]
4416 pub api_version: Option<String>,
4417 #[serde(skip_serializing_if = "Option::is_none")]
4418 pub kind: Option<String>,
4419 #[serde(default)]
4420 pub metadata: ListMeta,
4421 pub items: Vec<Event>,
4422}
4423
4424pub fn compute_expiration(
4425 explicit: Option<DateTime<Utc>>,
4426 ttl_days: Option<i32>,
4427) -> Result<Option<DateTime<Utc>>, ValidationError> {
4428 if let Some(ttl) = ttl_days {
4429 if ttl <= 0 {
4430 return Err(ValidationError::new("ttl_days"));
4431 }
4432 if explicit.is_some() {
4433 return Err(ValidationError::new("expires_at_conflict"));
4434 }
4435 return Ok(Some(Utc::now() + Duration::days(ttl.into())));
4436 }
4437 Ok(explicit)
4438}
4439
4440fn validate_grant_file_permission(
4441 request: &GrantFilePermissionRequest,
4442) -> Result<(), ValidationError> {
4443 if request.user_id.is_none()
4444 && request.team_id.is_none()
4445 && request
4446 .role
4447 .as_ref()
4448 .is_none_or(|value| value.trim().is_empty())
4449 {
4450 return Err(ValidationError::new("missing_grantee"));
4451 }
4452 Ok(())
4453}
4454
4455impl AuthProvider {
4456 #[must_use]
4457 pub fn as_storage(&self) -> (String, Option<String>) {
4458 match self {
4459 Self::Local => ("local".to_string(), None),
4460 Self::OAuth { provider } => ("oauth".to_string(), Some(provider.clone())),
4461 }
4462 }
4463
4464 #[must_use]
4465 pub fn from_storage(kind: &str, provider: Option<String>) -> Self {
4466 if kind.eq_ignore_ascii_case("oauth") {
4467 Self::OAuth {
4468 provider: provider.unwrap_or_else(|| "unknown".to_string()),
4469 }
4470 } else {
4471 Self::Local
4472 }
4473 }
4474}
4475
4476#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
4482#[serde(rename_all = "snake_case")]
4483pub enum MfaMethod {
4484 Totp,
4486}
4487
4488impl std::fmt::Display for MfaMethod {
4489 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4490 match self {
4491 Self::Totp => write!(f, "totp"),
4492 }
4493 }
4494}
4495
4496impl FromStr for MfaMethod {
4497 type Err = String;
4498
4499 fn from_str(s: &str) -> Result<Self, Self::Err> {
4500 match s.to_lowercase().as_str() {
4501 "totp" => Ok(Self::Totp),
4502 _ => Err(format!("Unknown MFA method: {s}")),
4503 }
4504 }
4505}
4506
4507#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4509pub struct MfaSecret {
4510 pub id: Uuid,
4511 pub user_id: Uuid,
4512 pub secret_encrypted: String,
4514 pub method: MfaMethod,
4515 pub is_enabled: bool,
4516 #[serde(skip_serializing_if = "Option::is_none")]
4517 pub verified_at: Option<DateTime<Utc>>,
4518 pub created_at: DateTime<Utc>,
4519 pub updated_at: DateTime<Utc>,
4520}
4521
4522#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4524pub struct MfaBackupCode {
4525 pub id: Uuid,
4526 pub user_id: Uuid,
4527 pub code_hash: String,
4529 #[serde(skip_serializing_if = "Option::is_none")]
4530 pub used_at: Option<DateTime<Utc>>,
4531 pub created_at: DateTime<Utc>,
4532}
4533
4534#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
4536#[serde(rename_all = "snake_case")]
4537pub enum PartialSessionPurpose {
4538 MfaVerify,
4540 MfaSetup,
4542}
4543
4544impl std::fmt::Display for PartialSessionPurpose {
4545 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4546 match self {
4547 Self::MfaVerify => write!(f, "mfa_verify"),
4548 Self::MfaSetup => write!(f, "mfa_setup"),
4549 }
4550 }
4551}
4552
4553impl FromStr for PartialSessionPurpose {
4554 type Err = String;
4555
4556 fn from_str(s: &str) -> Result<Self, Self::Err> {
4557 match s.to_lowercase().as_str() {
4558 "mfa_verify" => Ok(Self::MfaVerify),
4559 "mfa_setup" => Ok(Self::MfaSetup),
4560 _ => Err(format!("Unknown partial session purpose: {s}")),
4561 }
4562 }
4563}
4564
4565#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4567pub struct PartialSession {
4568 pub id: Uuid,
4569 pub user_id: Uuid,
4570 pub token_hash: String,
4572 pub purpose: PartialSessionPurpose,
4573 pub expires_at: DateTime<Utc>,
4574 #[serde(skip_serializing_if = "Option::is_none")]
4575 pub ip_address: Option<String>,
4576 pub created_at: DateTime<Utc>,
4577}
4578
4579#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
4581pub struct MfaSetupRequest {
4582 #[validate(length(equal = 6))]
4584 pub code: String,
4585}
4586
4587#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4589pub struct MfaSetupResponse {
4590 pub secret: String,
4592 pub qr_code_url: String,
4594 pub provisioning_uri: String,
4596}
4597
4598#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
4600pub struct MfaVerifyRequest {
4601 #[validate(length(min = 6, max = 32))]
4603 pub code: String,
4604 #[validate(length(min = 32, max = 64))]
4606 pub partial_token: String,
4607}
4608
4609#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4611pub struct MfaStatusResponse {
4612 pub enabled: bool,
4613 pub method: Option<MfaMethod>,
4614 pub backup_codes_remaining: i32,
4615 #[serde(skip_serializing_if = "Option::is_none")]
4616 pub verified_at: Option<DateTime<Utc>>,
4617}
4618
4619#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4621pub struct BackupCodesResponse {
4622 pub codes: Vec<String>,
4624 pub generated_at: DateTime<Utc>,
4625}
4626
4627#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
4633#[serde(rename_all = "snake_case")]
4634pub enum TokenPurpose {
4635 MagicLink,
4637 PasswordReset,
4639}
4640
4641impl std::fmt::Display for TokenPurpose {
4642 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4643 match self {
4644 Self::MagicLink => write!(f, "magic_link"),
4645 Self::PasswordReset => write!(f, "password_reset"),
4646 }
4647 }
4648}
4649
4650impl FromStr for TokenPurpose {
4651 type Err = String;
4652
4653 fn from_str(s: &str) -> Result<Self, Self::Err> {
4654 match s.to_lowercase().as_str() {
4655 "magic_link" => Ok(Self::MagicLink),
4656 "password_reset" => Ok(Self::PasswordReset),
4657 _ => Err(format!("Unknown token purpose: {s}")),
4658 }
4659 }
4660}
4661
4662#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4664pub struct MagicLink {
4665 pub id: Uuid,
4666 pub user_id: Uuid,
4667 pub token_hash: String,
4669 pub expires_at: DateTime<Utc>,
4670 #[serde(skip_serializing_if = "Option::is_none")]
4671 pub used_at: Option<DateTime<Utc>>,
4672 #[serde(skip_serializing_if = "Option::is_none")]
4673 pub ip_address: Option<String>,
4674 #[serde(skip_serializing_if = "Option::is_none")]
4675 pub user_agent: Option<String>,
4676 pub created_at: DateTime<Utc>,
4677}
4678
4679#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4681pub struct PasswordResetToken {
4682 pub id: Uuid,
4683 pub user_id: Uuid,
4684 pub token_hash: String,
4686 pub expires_at: DateTime<Utc>,
4687 #[serde(skip_serializing_if = "Option::is_none")]
4688 pub used_at: Option<DateTime<Utc>>,
4689 #[serde(skip_serializing_if = "Option::is_none")]
4690 pub ip_address: Option<String>,
4691 #[serde(skip_serializing_if = "Option::is_none")]
4692 pub user_agent: Option<String>,
4693 pub created_at: DateTime<Utc>,
4694}
4695
4696#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
4698pub struct MagicLinkRequest {
4699 #[validate(email)]
4700 pub email: String,
4701}
4702
4703#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
4705pub struct PasswordResetRequest {
4706 #[validate(email)]
4707 pub email: String,
4708}
4709
4710#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
4712pub struct PasswordResetCompleteRequest {
4713 #[validate(length(min = 32, max = 64))]
4714 pub token: String,
4715 #[validate(length(min = 12, max = 128))]
4716 pub new_password: String,
4717}
4718
4719#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
4721pub struct MagicLinkVerifyRequest {
4722 #[validate(length(min = 32, max = 64))]
4723 pub token: String,
4724}
4725
4726#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
4732#[serde(rename_all = "snake_case")]
4733pub enum DeviceType {
4734 Desktop,
4735 Mobile,
4736 Tablet,
4737 #[default]
4738 Unknown,
4739}
4740
4741#[derive(Debug, Clone, Default, Serialize, Deserialize, ToSchema)]
4743pub struct DeviceInfo {
4744 #[serde(skip_serializing_if = "Option::is_none")]
4745 pub browser: Option<String>,
4746 #[serde(skip_serializing_if = "Option::is_none")]
4747 pub os: Option<String>,
4748 pub device_type: DeviceType,
4749 #[serde(skip_serializing_if = "Option::is_none")]
4750 pub fingerprint: Option<String>,
4751}
4752
4753#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4755pub struct UserSession {
4756 pub id: Uuid,
4757 pub user_id: Uuid,
4758 pub session_token_hash: String,
4760 #[serde(skip_serializing_if = "Option::is_none")]
4761 pub refresh_token_hash: Option<String>,
4762 #[serde(skip_serializing_if = "Option::is_none")]
4763 pub device_fingerprint: Option<String>,
4764 #[serde(skip_serializing_if = "Option::is_none")]
4765 pub device_info: Option<String>,
4766 #[serde(skip_serializing_if = "Option::is_none")]
4767 pub browser: Option<String>,
4768 #[serde(skip_serializing_if = "Option::is_none")]
4769 pub os: Option<String>,
4770 #[serde(skip_serializing_if = "Option::is_none")]
4771 pub ip_address: Option<String>,
4772 #[serde(skip_serializing_if = "Option::is_none")]
4773 pub location_city: Option<String>,
4774 #[serde(skip_serializing_if = "Option::is_none")]
4775 pub location_country: Option<String>,
4776 pub is_current: bool,
4777 pub last_active_at: DateTime<Utc>,
4778 pub created_at: DateTime<Utc>,
4779 #[serde(skip_serializing_if = "Option::is_none")]
4780 pub revoked_at: Option<DateTime<Utc>>,
4781}
4782
4783#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4785pub struct SessionSummary {
4786 pub id: Uuid,
4787 #[serde(skip_serializing_if = "Option::is_none")]
4788 pub browser: Option<String>,
4789 #[serde(skip_serializing_if = "Option::is_none")]
4790 pub os: Option<String>,
4791 #[serde(skip_serializing_if = "Option::is_none")]
4792 pub ip_address: Option<String>,
4793 #[serde(skip_serializing_if = "Option::is_none")]
4794 pub location: Option<String>,
4795 pub is_current: bool,
4796 pub last_active_at: DateTime<Utc>,
4797 pub created_at: DateTime<Utc>,
4798}
4799
4800impl From<UserSession> for SessionSummary {
4801 fn from(session: UserSession) -> Self {
4802 let location = match (&session.location_city, &session.location_country) {
4803 (Some(city), Some(country)) => Some(format!("{city}, {country}")),
4804 (Some(city), None) => Some(city.clone()),
4805 (None, Some(country)) => Some(country.clone()),
4806 _ => None,
4807 };
4808
4809 Self {
4810 id: session.id,
4811 browser: session.browser,
4812 os: session.os,
4813 ip_address: session.ip_address,
4814 location,
4815 is_current: session.is_current,
4816 last_active_at: session.last_active_at,
4817 created_at: session.created_at,
4818 }
4819 }
4820}
4821
4822#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
4824pub struct RevokeSessionRequest {
4825 pub session_id: Uuid,
4826}
4827
4828#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4834pub struct WebAuthnCredential {
4835 pub id: Uuid,
4836 pub user_id: Uuid,
4837 #[serde(with = "base64_bytes")]
4839 pub credential_id: Vec<u8>,
4840 pub passkey: String,
4842 pub name: String,
4844 #[serde(skip_serializing_if = "Option::is_none")]
4845 pub aaguid: Option<Uuid>,
4846 #[serde(default, skip_serializing_if = "Vec::is_empty")]
4847 pub transports: Vec<String>,
4848 pub is_discoverable: bool,
4849 pub created_at: DateTime<Utc>,
4850 #[serde(skip_serializing_if = "Option::is_none")]
4851 pub last_used_at: Option<DateTime<Utc>>,
4852 pub updated_at: DateTime<Utc>,
4853}
4854
4855#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4857pub struct WebAuthnChallenge {
4858 pub id: Uuid,
4859 #[serde(skip_serializing_if = "Option::is_none")]
4860 pub user_id: Option<Uuid>,
4861 pub challenge_hash: String,
4863 pub state_encrypted: String,
4865 pub expires_at: DateTime<Utc>,
4866 pub created_at: DateTime<Utc>,
4867}
4868
4869#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4871pub struct PasskeySummary {
4872 pub id: Uuid,
4873 pub name: String,
4874 #[serde(default, skip_serializing_if = "Vec::is_empty")]
4875 pub transports: Vec<String>,
4876 pub is_discoverable: bool,
4877 pub created_at: DateTime<Utc>,
4878 #[serde(skip_serializing_if = "Option::is_none")]
4879 pub last_used_at: Option<DateTime<Utc>>,
4880}
4881
4882impl From<WebAuthnCredential> for PasskeySummary {
4883 fn from(cred: WebAuthnCredential) -> Self {
4884 Self {
4885 id: cred.id,
4886 name: cred.name,
4887 transports: cred.transports,
4888 is_discoverable: cred.is_discoverable,
4889 created_at: cred.created_at,
4890 last_used_at: cred.last_used_at,
4891 }
4892 }
4893}
4894
4895#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
4897pub struct RenamePasskeyRequest {
4898 #[validate(length(min = 1, max = 100))]
4899 pub name: String,
4900}
4901
4902#[derive(Debug, Clone, Serialize, Deserialize, Validate, ToSchema)]
4904pub struct PasskeyRegisterStartRequest {
4905 #[validate(length(min = 1, max = 100))]
4906 pub name: Option<String>,
4907}
4908
4909#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, ToSchema)]
4914#[serde(rename_all = "snake_case")]
4915pub enum StorageBucketVersioning {
4916 Disabled,
4917 Enabled,
4918 Suspended,
4919}
4920
4921#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, ToSchema)]
4922#[serde(rename_all = "snake_case")]
4923pub enum StorageReplicationStrategy {
4924 Mirror,
4925 Erasure,
4926}
4927
4928#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4929pub struct StorageObjectLock {
4930 pub enabled: bool,
4931 #[serde(skip_serializing_if = "Option::is_none")]
4932 pub default_retention_days: Option<i32>,
4933}
4934
4935#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4936pub struct StorageReplicationPolicy {
4937 pub factor: i32,
4938 pub strategy: StorageReplicationStrategy,
4939 #[serde(default, skip_serializing_if = "Vec::is_empty")]
4940 pub zones: Vec<String>,
4941 #[serde(skip_serializing_if = "Option::is_none")]
4942 pub min_success: Option<i32>,
4943}
4944
4945#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4946pub struct StorageCacheTier {
4947 #[serde(skip_serializing_if = "Option::is_none")]
4948 pub max_bytes: Option<i64>,
4949 #[serde(skip_serializing_if = "Option::is_none")]
4950 pub ttl_seconds: Option<i64>,
4951}
4952
4953#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4954pub struct StorageCachePolicy {
4955 #[serde(skip_serializing_if = "Option::is_none")]
4956 pub memory: Option<StorageCacheTier>,
4957 #[serde(skip_serializing_if = "Option::is_none")]
4958 pub nvme: Option<StorageCacheTier>,
4959}
4960
4961#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4962pub struct StorageLifecyclePolicy {
4963 #[serde(skip_serializing_if = "Option::is_none")]
4964 pub expire_days: Option<i32>,
4965 #[serde(skip_serializing_if = "Option::is_none")]
4966 pub transition_days: Option<i32>,
4967 #[serde(skip_serializing_if = "Option::is_none")]
4968 pub transition_class: Option<String>,
4969}
4970
4971#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4972pub struct StorageQuota {
4973 #[serde(skip_serializing_if = "Option::is_none")]
4974 pub max_bytes: Option<i64>,
4975 #[serde(skip_serializing_if = "Option::is_none")]
4976 pub max_objects: Option<i64>,
4977}
4978
4979#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
4980pub struct StorageBucket {
4981 pub id: Uuid,
4982 pub organization_id: Uuid,
4983 pub name: String,
4984 pub region: String,
4985 pub versioning: StorageBucketVersioning,
4986 #[serde(skip_serializing_if = "Option::is_none")]
4987 pub object_lock: Option<StorageObjectLock>,
4988 #[serde(skip_serializing_if = "Option::is_none")]
4989 pub replication: Option<StorageReplicationPolicy>,
4990 #[serde(skip_serializing_if = "Option::is_none")]
4991 pub cache_policy: Option<StorageCachePolicy>,
4992 #[serde(skip_serializing_if = "Option::is_none")]
4993 pub lifecycle: Option<StorageLifecyclePolicy>,
4994 #[serde(skip_serializing_if = "Option::is_none")]
4995 pub quota: Option<StorageQuota>,
4996 #[serde(default, skip_serializing_if = "Vec::is_empty")]
4997 pub tags: Vec<String>,
4998 pub created_at: DateTime<Utc>,
4999 pub updated_at: DateTime<Utc>,
5000}
5001
5002#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
5003pub struct StorageBucketList {
5004 pub items: Vec<StorageBucket>,
5005 #[serde(skip_serializing_if = "Option::is_none")]
5006 pub next_cursor: Option<String>,
5007}
5008
5009#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
5010pub struct StorageObject {
5011 pub bucket_id: Uuid,
5012 pub key: String,
5013 pub size_bytes: i64,
5014 #[serde(skip_serializing_if = "Option::is_none")]
5015 pub etag: Option<String>,
5016 #[serde(skip_serializing_if = "Option::is_none")]
5017 pub content_type: Option<String>,
5018 #[serde(skip_serializing_if = "Option::is_none")]
5019 pub version_id: Option<String>,
5020 pub created_at: DateTime<Utc>,
5021 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
5022 pub metadata: HashMap<String, String>,
5023}
5024
5025#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
5026pub struct StorageObjectList {
5027 pub items: Vec<StorageObject>,
5028 #[serde(skip_serializing_if = "Option::is_none")]
5029 pub next_cursor: Option<String>,
5030}
5031
5032#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, ToSchema)]
5033#[serde(rename_all = "snake_case")]
5034pub enum StorageVolumeStatus {
5035 Available,
5036 Bound,
5037 InUse,
5038 Error,
5039}
5040
5041#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
5042pub struct StorageVolume {
5043 pub id: Uuid,
5044 pub organization_id: Uuid,
5045 pub name: String,
5046 pub size_bytes: i64,
5047 #[serde(skip_serializing_if = "Option::is_none")]
5048 pub filesystem: Option<String>,
5049 #[serde(skip_serializing_if = "Option::is_none")]
5050 pub replica_count: Option<i32>,
5051 #[serde(skip_serializing_if = "Option::is_none")]
5052 pub storage_class: Option<String>,
5053 pub status: StorageVolumeStatus,
5054 #[serde(skip_serializing_if = "Option::is_none")]
5055 pub cache_policy: Option<StorageCachePolicy>,
5056 pub created_at: DateTime<Utc>,
5057 pub updated_at: DateTime<Utc>,
5058}
5059
5060#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
5061pub struct StorageVolumeList {
5062 pub items: Vec<StorageVolume>,
5063 #[serde(skip_serializing_if = "Option::is_none")]
5064 pub next_cursor: Option<String>,
5065}
5066
5067#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, ToSchema)]
5068#[serde(rename_all = "snake_case")]
5069pub enum StorageDriveType {
5070 Personal,
5071 Shared,
5072 Project,
5073 Compute,
5074}
5075
5076#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
5077pub struct StorageDrive {
5078 pub id: Uuid,
5079 pub organization_id: Uuid,
5080 pub name: String,
5081 pub drive_type: StorageDriveType,
5082 #[serde(skip_serializing_if = "Option::is_none")]
5083 pub root_folder_id: Option<Uuid>,
5084 pub created_at: DateTime<Utc>,
5085 pub updated_at: DateTime<Utc>,
5086}
5087
5088#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
5089pub struct StorageDriveList {
5090 pub items: Vec<StorageDrive>,
5091 #[serde(skip_serializing_if = "Option::is_none")]
5092 pub next_cursor: Option<String>,
5093}
5094
5095#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
5096pub struct StorageContentRef {
5097 pub bucket_id: Uuid,
5098 pub key: String,
5099}
5100
5101#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
5102pub struct StorageFile {
5103 pub id: Uuid,
5104 pub organization_id: Uuid,
5105 pub drive_id: Uuid,
5106 pub name: String,
5107 #[serde(skip_serializing_if = "Option::is_none")]
5108 pub mime_type: Option<String>,
5109 #[serde(skip_serializing_if = "Option::is_none")]
5110 pub size_bytes: Option<i64>,
5111 #[serde(default, skip_serializing_if = "Vec::is_empty")]
5112 pub parents: Vec<Uuid>,
5113 pub trashed: bool,
5114 pub version: i32,
5115 #[serde(skip_serializing_if = "Option::is_none")]
5116 pub content_ref: Option<StorageContentRef>,
5117 pub created_at: DateTime<Utc>,
5118 pub updated_at: DateTime<Utc>,
5119}
5120
5121#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
5122pub struct StorageFileList {
5123 pub items: Vec<StorageFile>,
5124 #[serde(skip_serializing_if = "Option::is_none")]
5125 pub next_cursor: Option<String>,
5126}
5127
5128#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, ToSchema)]
5129#[serde(rename_all = "snake_case")]
5130pub enum StoragePermissionResourceKind {
5131 Bucket,
5132 Drive,
5133 File,
5134 Volume,
5135}
5136
5137#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, ToSchema)]
5138#[serde(rename_all = "snake_case")]
5139pub enum StoragePermissionSubjectType {
5140 User,
5141 Group,
5142 ServiceAccount,
5143}
5144
5145#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, ToSchema)]
5146#[serde(rename_all = "snake_case")]
5147pub enum StoragePermissionRole {
5148 Owner,
5149 Admin,
5150 Editor,
5151 Viewer,
5152 Commenter,
5153}
5154
5155#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
5156pub struct StoragePermission {
5157 pub id: Uuid,
5158 pub organization_id: Uuid,
5159 pub resource_kind: StoragePermissionResourceKind,
5160 pub resource_id: Uuid,
5161 pub subject_type: StoragePermissionSubjectType,
5162 pub subject_id: Uuid,
5163 pub role: StoragePermissionRole,
5164 pub allow_file_discovery: bool,
5165 pub created_at: DateTime<Utc>,
5166 pub updated_at: DateTime<Utc>,
5167}
5168
5169#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
5170pub struct StoragePermissionList {
5171 pub items: Vec<StoragePermission>,
5172 #[serde(skip_serializing_if = "Option::is_none")]
5173 pub next_cursor: Option<String>,
5174}
5175
5176#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, ToSchema)]
5177#[serde(rename_all = "snake_case")]
5178pub enum StorageServiceAccountStatus {
5179 Active,
5180 Disabled,
5181}
5182
5183impl StorageServiceAccountStatus {
5184 #[must_use]
5185 pub const fn as_str(&self) -> &'static str {
5186 match self {
5187 Self::Active => "active",
5188 Self::Disabled => "disabled",
5189 }
5190 }
5191}
5192
5193impl FromStr for StorageServiceAccountStatus {
5194 type Err = ();
5195
5196 fn from_str(value: &str) -> Result<Self, Self::Err> {
5197 match value {
5198 "active" => Ok(Self::Active),
5199 "disabled" => Ok(Self::Disabled),
5200 _ => Err(()),
5201 }
5202 }
5203}
5204
5205#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, ToSchema)]
5206#[serde(transparent)]
5207pub struct StorageServiceAccountScope(pub String);
5208
5209impl StorageServiceAccountScope {
5210 #[must_use]
5211 pub fn new(value: impl Into<String>) -> Self {
5212 Self(value.into())
5213 }
5214
5215 #[must_use]
5216 pub fn as_str(&self) -> &str {
5217 &self.0
5218 }
5219}
5220
5221#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
5222pub struct StorageServiceAccount {
5223 pub id: Uuid,
5224 pub organization_id: Uuid,
5225 pub name: String,
5226 #[serde(skip_serializing_if = "Option::is_none")]
5227 pub description: Option<String>,
5228 #[serde(skip_serializing_if = "Option::is_none")]
5229 pub scopes: Option<Vec<StorageServiceAccountScope>>,
5230 pub status: StorageServiceAccountStatus,
5231 pub created_by: Uuid,
5232 pub created_at: DateTime<Utc>,
5233 pub updated_at: DateTime<Utc>,
5234 #[serde(skip_serializing_if = "Option::is_none")]
5235 pub last_used_at: Option<DateTime<Utc>>,
5236}
5237
5238#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
5239pub struct StorageServiceAccountList {
5240 pub items: Vec<StorageServiceAccount>,
5241 #[serde(skip_serializing_if = "Option::is_none")]
5242 pub next_cursor: Option<String>,
5243}
5244
5245#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, ToSchema)]
5246#[serde(rename_all = "snake_case")]
5247pub enum StorageAccessKeyStatus {
5248 Active,
5249 Revoked,
5250 Expired,
5251}
5252
5253impl StorageAccessKeyStatus {
5254 #[must_use]
5255 pub const fn as_str(&self) -> &'static str {
5256 match self {
5257 Self::Active => "active",
5258 Self::Revoked => "revoked",
5259 Self::Expired => "expired",
5260 }
5261 }
5262}
5263
5264impl FromStr for StorageAccessKeyStatus {
5265 type Err = ();
5266
5267 fn from_str(value: &str) -> Result<Self, Self::Err> {
5268 match value {
5269 "active" => Ok(Self::Active),
5270 "revoked" => Ok(Self::Revoked),
5271 "expired" => Ok(Self::Expired),
5272 _ => Err(()),
5273 }
5274 }
5275}
5276
5277#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
5278pub struct StorageAccessKey {
5279 pub id: Uuid,
5280 pub service_account_id: Uuid,
5281 pub access_key: String,
5282 pub status: StorageAccessKeyStatus,
5283 #[serde(skip_serializing_if = "Option::is_none")]
5284 pub secret_preview: Option<String>,
5285 #[serde(skip_serializing_if = "Option::is_none")]
5286 pub expires_at: Option<DateTime<Utc>>,
5287 #[serde(skip_serializing_if = "Option::is_none")]
5288 pub last_used_at: Option<DateTime<Utc>>,
5289 pub created_at: DateTime<Utc>,
5290 pub updated_at: DateTime<Utc>,
5291}
5292
5293#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
5294pub struct StorageAccessKeyWithSecret {
5295 #[serde(flatten)]
5296 pub access_key: StorageAccessKey,
5297 pub secret_key: String,
5298}
5299
5300#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
5301pub struct StorageAccessKeyList {
5302 pub items: Vec<StorageAccessKey>,
5303 #[serde(skip_serializing_if = "Option::is_none")]
5304 pub next_cursor: Option<String>,
5305}
5306
5307#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
5308pub struct CreateStorageServiceAccountRequest {
5309 pub name: String,
5310 #[serde(skip_serializing_if = "Option::is_none")]
5311 pub description: Option<String>,
5312 #[serde(skip_serializing_if = "Option::is_none")]
5313 pub scopes: Option<Vec<StorageServiceAccountScope>>,
5314}
5315
5316#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
5317pub struct UpdateStorageServiceAccountRequest {
5318 #[serde(skip_serializing_if = "Option::is_none")]
5319 pub name: Option<String>,
5320 #[serde(skip_serializing_if = "Option::is_none")]
5321 pub description: Option<Option<String>>,
5322 #[serde(skip_serializing_if = "Option::is_none")]
5323 pub scopes: Option<Option<Vec<StorageServiceAccountScope>>>,
5324 #[serde(skip_serializing_if = "Option::is_none")]
5325 pub status: Option<StorageServiceAccountStatus>,
5326}
5327
5328#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
5329pub struct CreateStorageAccessKeyRequest {
5330 #[serde(skip_serializing_if = "Option::is_none")]
5331 pub expires_at: Option<DateTime<Utc>>,
5332 #[serde(skip_serializing_if = "Option::is_none")]
5333 pub ttl_days: Option<i32>,
5334}
5335
5336#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
5337pub struct RotateStorageAccessKeyRequest {
5338 #[serde(skip_serializing_if = "Option::is_none")]
5339 pub expires_at: Option<DateTime<Utc>>,
5340 #[serde(skip_serializing_if = "Option::is_none")]
5341 pub ttl_days: Option<i32>,
5342 #[serde(skip_serializing_if = "Option::is_none")]
5343 pub reason: Option<String>,
5344}
5345
5346#[derive(Debug, Clone)]
5347pub struct NewStorageServiceAccount {
5348 pub id: Uuid,
5349 pub organization_id: Uuid,
5350 pub name: String,
5351 pub description: Option<String>,
5352 pub scopes: Option<Vec<StorageServiceAccountScope>>,
5353 pub status: StorageServiceAccountStatus,
5354 pub created_by: Uuid,
5355 pub created_at: DateTime<Utc>,
5356 pub updated_at: DateTime<Utc>,
5357 pub last_used_at: Option<DateTime<Utc>>,
5358}
5359
5360#[derive(Debug, Clone)]
5361pub struct StorageServiceAccountUpdate {
5362 pub name: Option<String>,
5363 pub description: Option<Option<String>>,
5364 pub scopes: Option<Option<Vec<StorageServiceAccountScope>>>,
5365 pub status: Option<StorageServiceAccountStatus>,
5366 pub updated_at: DateTime<Utc>,
5367 pub last_used_at: Option<Option<DateTime<Utc>>>,
5368}
5369
5370impl StorageServiceAccountUpdate {
5371 #[must_use]
5372 pub fn new(updated_at: DateTime<Utc>) -> Self {
5373 Self {
5374 name: None,
5375 description: None,
5376 scopes: None,
5377 status: None,
5378 updated_at,
5379 last_used_at: None,
5380 }
5381 }
5382}
5383
5384#[derive(Debug, Clone)]
5385pub struct NewStorageAccessKey {
5386 pub id: Uuid,
5387 pub service_account_id: Uuid,
5388 pub access_key: String,
5389 pub secret_hash: String,
5390 pub secret_preview: Option<String>,
5391 pub status: StorageAccessKeyStatus,
5392 pub created_at: DateTime<Utc>,
5393 pub updated_at: DateTime<Utc>,
5394 pub expires_at: Option<DateTime<Utc>>,
5395 pub last_used_at: Option<DateTime<Utc>>,
5396}
5397
5398#[derive(Debug, Clone)]
5399pub struct StorageAccessKeyUpdate {
5400 pub status: Option<StorageAccessKeyStatus>,
5401 pub secret_hash: Option<String>,
5402 pub secret_preview: Option<Option<String>>,
5403 pub expires_at: Option<Option<DateTime<Utc>>>,
5404 pub updated_at: DateTime<Utc>,
5405 pub last_used_at: Option<Option<DateTime<Utc>>>,
5406}
5407
5408impl StorageAccessKeyUpdate {
5409 #[must_use]
5410 pub fn new(updated_at: DateTime<Utc>) -> Self {
5411 Self {
5412 status: None,
5413 secret_hash: None,
5414 secret_preview: None,
5415 expires_at: None,
5416 updated_at,
5417 last_used_at: None,
5418 }
5419 }
5420}
5421
5422#[derive(Debug, Clone)]
5423pub struct StoredStorageAccessKey {
5424 pub access_key: StorageAccessKey,
5425 pub secret_hash: String,
5426}
5427
5428mod base64_bytes {
5430 use base64::{engine::general_purpose::STANDARD, Engine};
5431 use serde::{Deserialize, Deserializer, Serializer};
5432
5433 pub fn serialize<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
5434 where
5435 S: Serializer,
5436 {
5437 serializer.serialize_str(&STANDARD.encode(bytes))
5438 }
5439
5440 pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
5441 where
5442 D: Deserializer<'de>,
5443 {
5444 let s = String::deserialize(deserializer)?;
5445 STANDARD.decode(&s).map_err(serde::de::Error::custom)
5446 }
5447}